From 2895ad78dbdb43e57fc34558b4530b4e105fc72d Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 1 Feb 2024 18:10:29 +0300 Subject: Turn libodb-mssql repository into package for muti-package repository --- .gitignore | 37 - INSTALL | 99 - INSTALL-GIT | 78 - LICENSE | 21 - Makefile.am | 10 - NCUEL | 294 --- NEWS | 1 - README | 20 - README-GIT | 5 - bootstrap | 16 - build/.gitignore | 3 - build/bootstrap.build | 10 - build/bootstrap.make | 70 - build/export.build | 9 - build/export/libodb-mssql/stub.make | 8 - build/import/cli/cli-cxx.make | 47 - build/import/cli/configuration-rules.make | 13 - build/import/cli/configure | 53 - build/import/cli/stub.make | 28 - build/import/libodb-mssql/configuration-rules.make | 13 - build/import/libodb-mssql/configure | 53 - build/import/libodb-mssql/stub.make | 28 - build/import/libodb/configuration-rules.make | 13 - build/import/libodb/configure | 53 - build/import/libodb/stub.make | 28 - build/import/libodbc/configuration-rules.make | 13 - build/import/libodbc/configure | 28 - build/import/libodbc/stub.make | 22 - build/import/libodbc/version | 1 - build/root.build | 19 - buildfile | 9 - configure.ac | 57 - libodb-mssql-vc10.sln | 26 - libodb-mssql-vc11.sln | 26 - libodb-mssql-vc12.sln | 28 - libodb-mssql-vc8.sln | 26 - libodb-mssql-vc9.sln | 26 - libodb-mssql.pc.in | 14 - libodb-mssql/.gitignore | 25 + libodb-mssql/INSTALL | 6 + libodb-mssql/LICENSE | 21 + libodb-mssql/NCUEL | 294 +++ libodb-mssql/README | 20 + libodb-mssql/build/.gitignore | 3 + libodb-mssql/build/bootstrap.build | 10 + libodb-mssql/build/export.build | 9 + libodb-mssql/build/root.build | 19 + libodb-mssql/buildfile | 9 + libodb-mssql/manifest | 23 + libodb-mssql/odb/mssql/auto-handle.cxx | 17 + libodb-mssql/odb/mssql/auto-handle.hxx | 88 + libodb-mssql/odb/mssql/binding.hxx | 65 + libodb-mssql/odb/mssql/buildfile | 165 ++ libodb-mssql/odb/mssql/connection-factory.cxx | 159 ++ libodb-mssql/odb/mssql/connection-factory.hxx | 134 + libodb-mssql/odb/mssql/connection.cxx | 287 +++ libodb-mssql/odb/mssql/connection.hxx | 187 ++ libodb-mssql/odb/mssql/connection.ixx | 44 + libodb-mssql/odb/mssql/container-statements.hxx | 353 +++ libodb-mssql/odb/mssql/container-statements.txx | 96 + libodb-mssql/odb/mssql/database.cxx | 580 +++++ libodb-mssql/odb/mssql/database.hxx | 629 +++++ libodb-mssql/odb/mssql/database.ixx | 644 +++++ libodb-mssql/odb/mssql/details/.gitignore | 1 + .../odb/mssql/details/build2/config-stub.h | 5 + .../odb/mssql/details/build2/config-vc-stub.h | 5 + libodb-mssql/odb/mssql/details/build2/config-vc.h | 15 + libodb-mssql/odb/mssql/details/build2/config.h | 17 + libodb-mssql/odb/mssql/details/config-vc.h | 5 + libodb-mssql/odb/mssql/details/config.h.in | 12 + libodb-mssql/odb/mssql/details/config.hxx | 21 + libodb-mssql/odb/mssql/details/conversion.hxx | 58 + libodb-mssql/odb/mssql/details/export.hxx | 78 + libodb-mssql/odb/mssql/details/options.cli | 63 + .../pregenerated/odb/mssql/details/options.cxx | 1125 ++++++++ .../pregenerated/odb/mssql/details/options.hxx | 562 ++++ .../pregenerated/odb/mssql/details/options.ixx | 372 +++ libodb-mssql/odb/mssql/error.cxx | 273 ++ libodb-mssql/odb/mssql/error.hxx | 40 + libodb-mssql/odb/mssql/exceptions.cxx | 109 + libodb-mssql/odb/mssql/exceptions.hxx | 138 + libodb-mssql/odb/mssql/forward.hxx | 91 + libodb-mssql/odb/mssql/mssql-fwd.hxx | 216 ++ libodb-mssql/odb/mssql/mssql-types.hxx | 161 ++ libodb-mssql/odb/mssql/mssql.hxx | 69 + libodb-mssql/odb/mssql/no-id-object-result.hxx | 85 + libodb-mssql/odb/mssql/no-id-object-result.txx | 154 ++ libodb-mssql/odb/mssql/no-id-object-statements.hxx | 137 + libodb-mssql/odb/mssql/no-id-object-statements.txx | 39 + .../odb/mssql/polymorphic-object-result.hxx | 99 + .../odb/mssql/polymorphic-object-result.txx | 325 +++ .../odb/mssql/polymorphic-object-statements.hxx | 469 ++++ .../odb/mssql/polymorphic-object-statements.txx | 140 + libodb-mssql/odb/mssql/prepared-query.cxx | 15 + libodb-mssql/odb/mssql/prepared-query.hxx | 34 + libodb-mssql/odb/mssql/query-const-expr.cxx | 14 + libodb-mssql/odb/mssql/query-dynamic.cxx | 157 ++ libodb-mssql/odb/mssql/query-dynamic.hxx | 32 + libodb-mssql/odb/mssql/query-dynamic.ixx | 30 + libodb-mssql/odb/mssql/query-dynamic.txx | 25 + libodb-mssql/odb/mssql/query.cxx | 406 +++ libodb-mssql/odb/mssql/query.hxx | 2711 ++++++++++++++++++++ libodb-mssql/odb/mssql/query.ixx | 34 + libodb-mssql/odb/mssql/query.txx | 169 ++ libodb-mssql/odb/mssql/section-statements.hxx | 201 ++ libodb-mssql/odb/mssql/section-statements.txx | 50 + libodb-mssql/odb/mssql/simple-object-result.hxx | 89 + libodb-mssql/odb/mssql/simple-object-result.txx | 186 ++ .../odb/mssql/simple-object-statements.cxx | 15 + .../odb/mssql/simple-object-statements.hxx | 606 +++++ .../odb/mssql/simple-object-statements.ixx | 68 + .../odb/mssql/simple-object-statements.txx | 173 ++ libodb-mssql/odb/mssql/statement-cache.hxx | 59 + libodb-mssql/odb/mssql/statement-cache.txx | 60 + libodb-mssql/odb/mssql/statement-processing.cxx | 356 +++ libodb-mssql/odb/mssql/statement.cxx | 1740 +++++++++++++ libodb-mssql/odb/mssql/statement.hxx | 558 ++++ libodb-mssql/odb/mssql/statement.ixx | 41 + libodb-mssql/odb/mssql/statements-base.cxx | 15 + libodb-mssql/odb/mssql/statements-base.hxx | 63 + libodb-mssql/odb/mssql/tracer.cxx | 60 + libodb-mssql/odb/mssql/tracer.hxx | 61 + libodb-mssql/odb/mssql/traits-calls.hxx | 190 ++ libodb-mssql/odb/mssql/traits.cxx | 616 +++++ libodb-mssql/odb/mssql/traits.hxx | 2176 ++++++++++++++++ libodb-mssql/odb/mssql/traits.txx | 399 +++ libodb-mssql/odb/mssql/transaction-impl.cxx | 103 + libodb-mssql/odb/mssql/transaction-impl.hxx | 49 + libodb-mssql/odb/mssql/transaction.cxx | 26 + libodb-mssql/odb/mssql/transaction.hxx | 88 + libodb-mssql/odb/mssql/transaction.ixx | 57 + libodb-mssql/odb/mssql/version-build2-stub.hxx | 4 + libodb-mssql/odb/mssql/version-build2.hxx | 0 libodb-mssql/odb/mssql/version-build2.hxx.in | 42 + libodb-mssql/odb/mssql/version.hxx | 48 + libodb-mssql/odb/mssql/view-result.hxx | 85 + libodb-mssql/odb/mssql/view-result.txx | 153 ++ libodb-mssql/odb/mssql/view-statements.hxx | 83 + libodb-mssql/odb/mssql/view-statements.txx | 30 + libodb-mssql/tests/.gitignore | 1 + libodb-mssql/tests/basics/buildfile | 6 + libodb-mssql/tests/basics/driver.cxx | 37 + libodb-mssql/tests/build/.gitignore | 3 + libodb-mssql/tests/build/bootstrap.build | 8 + libodb-mssql/tests/build/root.build | 23 + libodb-mssql/tests/buildfile | 4 + m4/acx-pthread.m4 | 259 -- m4/disable-rpath.m4 | 24 - m4/libodb.m4 | 81 - m4/libodbc.m4 | 70 - m4/libtool-link.m4 | 45 - m4/pkgconfig.m4 | 11 - m4/static-lib.m4 | 17 - m4/threads.m4 | 68 - makefile | 35 - manifest | 23 - odb/mssql/Makefile.am | 14 - odb/mssql/auto-handle.cxx | 17 - odb/mssql/auto-handle.hxx | 88 - odb/mssql/binding.hxx | 65 - odb/mssql/buildfile | 165 -- odb/mssql/connection-factory.cxx | 159 -- odb/mssql/connection-factory.hxx | 134 - odb/mssql/connection.cxx | 287 --- odb/mssql/connection.hxx | 187 -- odb/mssql/connection.ixx | 44 - odb/mssql/container-statements.hxx | 353 --- odb/mssql/container-statements.txx | 96 - odb/mssql/database.cxx | 580 ----- odb/mssql/database.hxx | 629 ----- odb/mssql/database.ixx | 644 ----- odb/mssql/details/.gitignore | 1 - odb/mssql/details/build2/config-stub.h | 5 - odb/mssql/details/build2/config-vc-stub.h | 5 - odb/mssql/details/build2/config-vc.h | 15 - odb/mssql/details/build2/config.h | 17 - odb/mssql/details/config-vc.h | 5 - odb/mssql/details/config.h.in | 12 - odb/mssql/details/config.hxx | 21 - odb/mssql/details/conversion.hxx | 58 - odb/mssql/details/export.hxx | 78 - odb/mssql/details/options.cli | 63 - .../pregenerated/odb/mssql/details/options.cxx | 1125 -------- .../pregenerated/odb/mssql/details/options.hxx | 562 ---- .../pregenerated/odb/mssql/details/options.ixx | 372 --- odb/mssql/error.cxx | 273 -- odb/mssql/error.hxx | 40 - odb/mssql/exceptions.cxx | 109 - odb/mssql/exceptions.hxx | 138 - odb/mssql/forward.hxx | 91 - odb/mssql/libodb-mssql-vc10.vcxproj | 174 -- odb/mssql/libodb-mssql-vc10.vcxproj.filters | 19 - odb/mssql/libodb-mssql-vc11.vcxproj | 178 -- odb/mssql/libodb-mssql-vc11.vcxproj.filters | 19 - odb/mssql/libodb-mssql-vc12.vcxproj | 182 -- odb/mssql/libodb-mssql-vc12.vcxproj.filters | 19 - odb/mssql/libodb-mssql-vc8.vcproj | 352 --- odb/mssql/libodb-mssql-vc9.vcproj | 359 --- odb/mssql/makefile | 156 -- odb/mssql/mssql-fwd.hxx | 216 -- odb/mssql/mssql-types.hxx | 161 -- odb/mssql/mssql.hxx | 69 - odb/mssql/no-id-object-result.hxx | 85 - odb/mssql/no-id-object-result.txx | 154 -- odb/mssql/no-id-object-statements.hxx | 137 - odb/mssql/no-id-object-statements.txx | 39 - odb/mssql/polymorphic-object-result.hxx | 99 - odb/mssql/polymorphic-object-result.txx | 325 --- odb/mssql/polymorphic-object-statements.hxx | 469 ---- odb/mssql/polymorphic-object-statements.txx | 140 - odb/mssql/prepared-query.cxx | 15 - odb/mssql/prepared-query.hxx | 34 - odb/mssql/query-const-expr.cxx | 14 - odb/mssql/query-dynamic.cxx | 157 -- odb/mssql/query-dynamic.hxx | 32 - odb/mssql/query-dynamic.ixx | 30 - odb/mssql/query-dynamic.txx | 25 - odb/mssql/query.cxx | 406 --- odb/mssql/query.hxx | 2711 -------------------- odb/mssql/query.ixx | 34 - odb/mssql/query.txx | 169 -- odb/mssql/section-statements.hxx | 201 -- odb/mssql/section-statements.txx | 50 - odb/mssql/simple-object-result.hxx | 89 - odb/mssql/simple-object-result.txx | 186 -- odb/mssql/simple-object-statements.cxx | 15 - odb/mssql/simple-object-statements.hxx | 606 ----- odb/mssql/simple-object-statements.ixx | 68 - odb/mssql/simple-object-statements.txx | 173 -- odb/mssql/statement-cache.hxx | 59 - odb/mssql/statement-cache.txx | 60 - odb/mssql/statement-processing.cxx | 356 --- odb/mssql/statement.cxx | 1740 ------------- odb/mssql/statement.hxx | 558 ---- odb/mssql/statement.ixx | 41 - odb/mssql/statements-base.cxx | 15 - odb/mssql/statements-base.hxx | 63 - odb/mssql/tracer.cxx | 60 - odb/mssql/tracer.hxx | 61 - odb/mssql/traits-calls.hxx | 190 -- odb/mssql/traits.cxx | 616 ----- odb/mssql/traits.hxx | 2176 ---------------- odb/mssql/traits.txx | 399 --- odb/mssql/transaction-impl.cxx | 103 - odb/mssql/transaction-impl.hxx | 49 - odb/mssql/transaction.cxx | 26 - odb/mssql/transaction.hxx | 88 - odb/mssql/transaction.ixx | 57 - odb/mssql/version-build2-stub.hxx | 4 - odb/mssql/version-build2.hxx | 0 odb/mssql/version-build2.hxx.in | 42 - odb/mssql/version.hxx | 48 - odb/mssql/view-result.hxx | 85 - odb/mssql/view-result.txx | 153 -- odb/mssql/view-statements.hxx | 83 - odb/mssql/view-statements.txx | 30 - repositories.manifest | 10 - tests/.gitignore | 1 - tests/basics/buildfile | 6 - tests/basics/driver.cxx | 37 - tests/build/.gitignore | 3 - tests/build/bootstrap.build | 8 - tests/build/root.build | 23 - tests/buildfile | 4 - version.txt | 1 - 265 files changed, 21030 insertions(+), 24012 deletions(-) delete mode 100644 .gitignore delete mode 100644 INSTALL delete mode 100644 INSTALL-GIT delete mode 100644 LICENSE delete mode 100644 Makefile.am delete mode 100644 NCUEL delete mode 100644 NEWS delete mode 100644 README delete mode 100644 README-GIT delete mode 100755 bootstrap delete mode 100644 build/.gitignore delete mode 100644 build/bootstrap.build delete mode 100644 build/bootstrap.make delete mode 100644 build/export.build delete mode 100644 build/export/libodb-mssql/stub.make delete mode 100644 build/import/cli/cli-cxx.make delete mode 100644 build/import/cli/configuration-rules.make delete mode 100755 build/import/cli/configure delete mode 100644 build/import/cli/stub.make delete mode 100644 build/import/libodb-mssql/configuration-rules.make delete mode 100755 build/import/libodb-mssql/configure delete mode 100644 build/import/libodb-mssql/stub.make delete mode 100644 build/import/libodb/configuration-rules.make delete mode 100755 build/import/libodb/configure delete mode 100644 build/import/libodb/stub.make delete mode 100644 build/import/libodbc/configuration-rules.make delete mode 100755 build/import/libodbc/configure delete mode 100644 build/import/libodbc/stub.make delete mode 100644 build/import/libodbc/version delete mode 100644 build/root.build delete mode 100644 buildfile delete mode 100644 configure.ac delete mode 100644 libodb-mssql-vc10.sln delete mode 100644 libodb-mssql-vc11.sln delete mode 100644 libodb-mssql-vc12.sln delete mode 100644 libodb-mssql-vc8.sln delete mode 100644 libodb-mssql-vc9.sln delete mode 100644 libodb-mssql.pc.in create mode 100644 libodb-mssql/.gitignore create mode 100644 libodb-mssql/INSTALL create mode 100644 libodb-mssql/LICENSE create mode 100644 libodb-mssql/NCUEL create mode 100644 libodb-mssql/README create mode 100644 libodb-mssql/build/.gitignore create mode 100644 libodb-mssql/build/bootstrap.build create mode 100644 libodb-mssql/build/export.build create mode 100644 libodb-mssql/build/root.build create mode 100644 libodb-mssql/buildfile create mode 100644 libodb-mssql/manifest create mode 100644 libodb-mssql/odb/mssql/auto-handle.cxx create mode 100644 libodb-mssql/odb/mssql/auto-handle.hxx create mode 100644 libodb-mssql/odb/mssql/binding.hxx create mode 100644 libodb-mssql/odb/mssql/buildfile create mode 100644 libodb-mssql/odb/mssql/connection-factory.cxx create mode 100644 libodb-mssql/odb/mssql/connection-factory.hxx create mode 100644 libodb-mssql/odb/mssql/connection.cxx create mode 100644 libodb-mssql/odb/mssql/connection.hxx create mode 100644 libodb-mssql/odb/mssql/connection.ixx create mode 100644 libodb-mssql/odb/mssql/container-statements.hxx create mode 100644 libodb-mssql/odb/mssql/container-statements.txx create mode 100644 libodb-mssql/odb/mssql/database.cxx create mode 100644 libodb-mssql/odb/mssql/database.hxx create mode 100644 libodb-mssql/odb/mssql/database.ixx create mode 100644 libodb-mssql/odb/mssql/details/.gitignore create mode 100644 libodb-mssql/odb/mssql/details/build2/config-stub.h create mode 100644 libodb-mssql/odb/mssql/details/build2/config-vc-stub.h create mode 100644 libodb-mssql/odb/mssql/details/build2/config-vc.h create mode 100644 libodb-mssql/odb/mssql/details/build2/config.h create mode 100644 libodb-mssql/odb/mssql/details/config-vc.h create mode 100644 libodb-mssql/odb/mssql/details/config.h.in create mode 100644 libodb-mssql/odb/mssql/details/config.hxx create mode 100644 libodb-mssql/odb/mssql/details/conversion.hxx create mode 100644 libodb-mssql/odb/mssql/details/export.hxx create mode 100644 libodb-mssql/odb/mssql/details/options.cli create mode 100644 libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.cxx create mode 100644 libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.hxx create mode 100644 libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.ixx create mode 100644 libodb-mssql/odb/mssql/error.cxx create mode 100644 libodb-mssql/odb/mssql/error.hxx create mode 100644 libodb-mssql/odb/mssql/exceptions.cxx create mode 100644 libodb-mssql/odb/mssql/exceptions.hxx create mode 100644 libodb-mssql/odb/mssql/forward.hxx create mode 100644 libodb-mssql/odb/mssql/mssql-fwd.hxx create mode 100644 libodb-mssql/odb/mssql/mssql-types.hxx create mode 100644 libodb-mssql/odb/mssql/mssql.hxx create mode 100644 libodb-mssql/odb/mssql/no-id-object-result.hxx create mode 100644 libodb-mssql/odb/mssql/no-id-object-result.txx create mode 100644 libodb-mssql/odb/mssql/no-id-object-statements.hxx create mode 100644 libodb-mssql/odb/mssql/no-id-object-statements.txx create mode 100644 libodb-mssql/odb/mssql/polymorphic-object-result.hxx create mode 100644 libodb-mssql/odb/mssql/polymorphic-object-result.txx create mode 100644 libodb-mssql/odb/mssql/polymorphic-object-statements.hxx create mode 100644 libodb-mssql/odb/mssql/polymorphic-object-statements.txx create mode 100644 libodb-mssql/odb/mssql/prepared-query.cxx create mode 100644 libodb-mssql/odb/mssql/prepared-query.hxx create mode 100644 libodb-mssql/odb/mssql/query-const-expr.cxx create mode 100644 libodb-mssql/odb/mssql/query-dynamic.cxx create mode 100644 libodb-mssql/odb/mssql/query-dynamic.hxx create mode 100644 libodb-mssql/odb/mssql/query-dynamic.ixx create mode 100644 libodb-mssql/odb/mssql/query-dynamic.txx create mode 100644 libodb-mssql/odb/mssql/query.cxx create mode 100644 libodb-mssql/odb/mssql/query.hxx create mode 100644 libodb-mssql/odb/mssql/query.ixx create mode 100644 libodb-mssql/odb/mssql/query.txx create mode 100644 libodb-mssql/odb/mssql/section-statements.hxx create mode 100644 libodb-mssql/odb/mssql/section-statements.txx create mode 100644 libodb-mssql/odb/mssql/simple-object-result.hxx create mode 100644 libodb-mssql/odb/mssql/simple-object-result.txx create mode 100644 libodb-mssql/odb/mssql/simple-object-statements.cxx create mode 100644 libodb-mssql/odb/mssql/simple-object-statements.hxx create mode 100644 libodb-mssql/odb/mssql/simple-object-statements.ixx create mode 100644 libodb-mssql/odb/mssql/simple-object-statements.txx create mode 100644 libodb-mssql/odb/mssql/statement-cache.hxx create mode 100644 libodb-mssql/odb/mssql/statement-cache.txx create mode 100644 libodb-mssql/odb/mssql/statement-processing.cxx create mode 100644 libodb-mssql/odb/mssql/statement.cxx create mode 100644 libodb-mssql/odb/mssql/statement.hxx create mode 100644 libodb-mssql/odb/mssql/statement.ixx create mode 100644 libodb-mssql/odb/mssql/statements-base.cxx create mode 100644 libodb-mssql/odb/mssql/statements-base.hxx create mode 100644 libodb-mssql/odb/mssql/tracer.cxx create mode 100644 libodb-mssql/odb/mssql/tracer.hxx create mode 100644 libodb-mssql/odb/mssql/traits-calls.hxx create mode 100644 libodb-mssql/odb/mssql/traits.cxx create mode 100644 libodb-mssql/odb/mssql/traits.hxx create mode 100644 libodb-mssql/odb/mssql/traits.txx create mode 100644 libodb-mssql/odb/mssql/transaction-impl.cxx create mode 100644 libodb-mssql/odb/mssql/transaction-impl.hxx create mode 100644 libodb-mssql/odb/mssql/transaction.cxx create mode 100644 libodb-mssql/odb/mssql/transaction.hxx create mode 100644 libodb-mssql/odb/mssql/transaction.ixx create mode 100644 libodb-mssql/odb/mssql/version-build2-stub.hxx create mode 100644 libodb-mssql/odb/mssql/version-build2.hxx create mode 100644 libodb-mssql/odb/mssql/version-build2.hxx.in create mode 100644 libodb-mssql/odb/mssql/version.hxx create mode 100644 libodb-mssql/odb/mssql/view-result.hxx create mode 100644 libodb-mssql/odb/mssql/view-result.txx create mode 100644 libodb-mssql/odb/mssql/view-statements.hxx create mode 100644 libodb-mssql/odb/mssql/view-statements.txx create mode 100644 libodb-mssql/tests/.gitignore create mode 100644 libodb-mssql/tests/basics/buildfile create mode 100644 libodb-mssql/tests/basics/driver.cxx create mode 100644 libodb-mssql/tests/build/.gitignore create mode 100644 libodb-mssql/tests/build/bootstrap.build create mode 100644 libodb-mssql/tests/build/root.build create mode 100644 libodb-mssql/tests/buildfile delete mode 100644 m4/acx-pthread.m4 delete mode 100644 m4/disable-rpath.m4 delete mode 100644 m4/libodb.m4 delete mode 100644 m4/libodbc.m4 delete mode 100644 m4/libtool-link.m4 delete mode 100644 m4/pkgconfig.m4 delete mode 100644 m4/static-lib.m4 delete mode 100644 m4/threads.m4 delete mode 100644 makefile delete mode 100644 manifest delete mode 100644 odb/mssql/Makefile.am delete mode 100644 odb/mssql/auto-handle.cxx delete mode 100644 odb/mssql/auto-handle.hxx delete mode 100644 odb/mssql/binding.hxx delete mode 100644 odb/mssql/buildfile delete mode 100644 odb/mssql/connection-factory.cxx delete mode 100644 odb/mssql/connection-factory.hxx delete mode 100644 odb/mssql/connection.cxx delete mode 100644 odb/mssql/connection.hxx delete mode 100644 odb/mssql/connection.ixx delete mode 100644 odb/mssql/container-statements.hxx delete mode 100644 odb/mssql/container-statements.txx delete mode 100644 odb/mssql/database.cxx delete mode 100644 odb/mssql/database.hxx delete mode 100644 odb/mssql/database.ixx delete mode 100644 odb/mssql/details/.gitignore delete mode 100644 odb/mssql/details/build2/config-stub.h delete mode 100644 odb/mssql/details/build2/config-vc-stub.h delete mode 100644 odb/mssql/details/build2/config-vc.h delete mode 100644 odb/mssql/details/build2/config.h delete mode 100644 odb/mssql/details/config-vc.h delete mode 100644 odb/mssql/details/config.h.in delete mode 100644 odb/mssql/details/config.hxx delete mode 100644 odb/mssql/details/conversion.hxx delete mode 100644 odb/mssql/details/export.hxx delete mode 100644 odb/mssql/details/options.cli delete mode 100644 odb/mssql/details/pregenerated/odb/mssql/details/options.cxx delete mode 100644 odb/mssql/details/pregenerated/odb/mssql/details/options.hxx delete mode 100644 odb/mssql/details/pregenerated/odb/mssql/details/options.ixx delete mode 100644 odb/mssql/error.cxx delete mode 100644 odb/mssql/error.hxx delete mode 100644 odb/mssql/exceptions.cxx delete mode 100644 odb/mssql/exceptions.hxx delete mode 100644 odb/mssql/forward.hxx delete mode 100644 odb/mssql/libodb-mssql-vc10.vcxproj delete mode 100644 odb/mssql/libodb-mssql-vc10.vcxproj.filters delete mode 100644 odb/mssql/libodb-mssql-vc11.vcxproj delete mode 100644 odb/mssql/libodb-mssql-vc11.vcxproj.filters delete mode 100644 odb/mssql/libodb-mssql-vc12.vcxproj delete mode 100644 odb/mssql/libodb-mssql-vc12.vcxproj.filters delete mode 100644 odb/mssql/libodb-mssql-vc8.vcproj delete mode 100644 odb/mssql/libodb-mssql-vc9.vcproj delete mode 100644 odb/mssql/makefile delete mode 100644 odb/mssql/mssql-fwd.hxx delete mode 100644 odb/mssql/mssql-types.hxx delete mode 100644 odb/mssql/mssql.hxx delete mode 100644 odb/mssql/no-id-object-result.hxx delete mode 100644 odb/mssql/no-id-object-result.txx delete mode 100644 odb/mssql/no-id-object-statements.hxx delete mode 100644 odb/mssql/no-id-object-statements.txx delete mode 100644 odb/mssql/polymorphic-object-result.hxx delete mode 100644 odb/mssql/polymorphic-object-result.txx delete mode 100644 odb/mssql/polymorphic-object-statements.hxx delete mode 100644 odb/mssql/polymorphic-object-statements.txx delete mode 100644 odb/mssql/prepared-query.cxx delete mode 100644 odb/mssql/prepared-query.hxx delete mode 100644 odb/mssql/query-const-expr.cxx delete mode 100644 odb/mssql/query-dynamic.cxx delete mode 100644 odb/mssql/query-dynamic.hxx delete mode 100644 odb/mssql/query-dynamic.ixx delete mode 100644 odb/mssql/query-dynamic.txx delete mode 100644 odb/mssql/query.cxx delete mode 100644 odb/mssql/query.hxx delete mode 100644 odb/mssql/query.ixx delete mode 100644 odb/mssql/query.txx delete mode 100644 odb/mssql/section-statements.hxx delete mode 100644 odb/mssql/section-statements.txx delete mode 100644 odb/mssql/simple-object-result.hxx delete mode 100644 odb/mssql/simple-object-result.txx delete mode 100644 odb/mssql/simple-object-statements.cxx delete mode 100644 odb/mssql/simple-object-statements.hxx delete mode 100644 odb/mssql/simple-object-statements.ixx delete mode 100644 odb/mssql/simple-object-statements.txx delete mode 100644 odb/mssql/statement-cache.hxx delete mode 100644 odb/mssql/statement-cache.txx delete mode 100644 odb/mssql/statement-processing.cxx delete mode 100644 odb/mssql/statement.cxx delete mode 100644 odb/mssql/statement.hxx delete mode 100644 odb/mssql/statement.ixx delete mode 100644 odb/mssql/statements-base.cxx delete mode 100644 odb/mssql/statements-base.hxx delete mode 100644 odb/mssql/tracer.cxx delete mode 100644 odb/mssql/tracer.hxx delete mode 100644 odb/mssql/traits-calls.hxx delete mode 100644 odb/mssql/traits.cxx delete mode 100644 odb/mssql/traits.hxx delete mode 100644 odb/mssql/traits.txx delete mode 100644 odb/mssql/transaction-impl.cxx delete mode 100644 odb/mssql/transaction-impl.hxx delete mode 100644 odb/mssql/transaction.cxx delete mode 100644 odb/mssql/transaction.hxx delete mode 100644 odb/mssql/transaction.ixx delete mode 100644 odb/mssql/version-build2-stub.hxx delete mode 100644 odb/mssql/version-build2.hxx delete mode 100644 odb/mssql/version-build2.hxx.in delete mode 100644 odb/mssql/version.hxx delete mode 100644 odb/mssql/view-result.hxx delete mode 100644 odb/mssql/view-result.txx delete mode 100644 odb/mssql/view-statements.hxx delete mode 100644 odb/mssql/view-statements.txx delete mode 100644 repositories.manifest delete mode 100644 tests/.gitignore delete mode 100644 tests/basics/buildfile delete mode 100644 tests/basics/driver.cxx delete mode 100644 tests/build/.gitignore delete mode 100644 tests/build/bootstrap.build delete mode 100644 tests/build/root.build delete mode 100644 tests/buildfile delete mode 100644 version.txt diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 3004ad1..0000000 --- a/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -.bdep/ - -# Compiler/linker output. -# -*.d -*.t -*.i -*.ii -*.o -*.obj -*.so -*.dll -*.a -*.lib -*.exp -*.pdb -*.ilk -*.exe -*.exe.dlls/ -*.exe.manifest -*.pc - -*.l -*.l.cpp-options - -# Generated documentation. -# -*.pdf -*.ps - -# Generated build system files. -# -*-dynamic.make - -# Generated .gitignore files. -# -.gitignore diff --git a/INSTALL b/INSTALL deleted file mode 100644 index bdc072a..0000000 --- a/INSTALL +++ /dev/null @@ -1,99 +0,0 @@ -Prerequisites -============= - - - libodb http://www.codesynthesis.com/products/odb/ - - libodbc (UNIX only) http://www.unixodbc.org/ - - SQL Server Native Client http://msdn.microsoft.com/en-us/sqlserver/aa937733 - - -Building on UNIX -================ - -The following build instructions are for the Linux/UNIX/Mac OS X -operating systems as well as for Cygwin and MinGW on Windows. - -The standard autotools-based build system is used on these platforms. -After unpacking the source code archive, change to the libodb-mssql -package directory (referred to as libodb-mssql/ from now on) and run -the configure script: - -./configure - -To see the available configuration options run configure with --help: - -./configure --help - -The configure script expects the libodb and libodbc headers and -libraries to be installed in a directory where the C++ compiler and -linker will search for them by default (normally /usr and /usr/local). -If these libraries are installed in other directories, you can use the -CPPFLAGS and LDFLAGS configure variables to specify their locations, -for example: - -./configure CPPFLAGS=-I/opt/libodb/include LDFLAGS=-L/opt/libodb/lib - -If libodb is not installed and you would like to use its build -directory instead, you can use the --with-libodb configure option -to specify its location, for example: - -./configure --with-libodb=/tmp/libodb - -As another example, the following configure command only builds shared -libraries, uses the specified C++ compiler, and compiles with optimization -and without debug information: - -./configure --disable-static CXX=g++-4.5 CXXFLAGS=-O3 - -Once configuration is complete, run make to build libodb-mssql: - -make - -Once the build is completed successfully, you can install the libodb-mssql -headers and libraries using the install target (you may need to do this -step as root depending on the installation directory): - -make install - - -Building on Windows -=================== - -The following build instructions are for Windows using Microsoft Visual -Studio. If you would like to build libodb-mssql with GCC either using -Cygwin or MinGW, refer to the "Building on UNIX" section above. - -The standard Visual Studio project and solution files are used on this -platform. The provided project files expect the libodb header and import -library directories to be in the VC++ Directories Include and Library -search lists. See the INSTALL file in the libodb package directory for -more information on how to setup the VC++ Directories. - -To build libodb-mssql, unpack the source code archive and open the -libodb-mssql-vc.sln file located in the libodb-mssql package -directory (referred to as libodb-mssql\ from now on). Here is the -version of Visual Studio that you are using. Once the solution is open, -select the desired build configuration (Debug or Release) and platform -(Win32 or x64) and build the solution. - -The resulting 32-bit DLLs and import libraries are placed into the -libodb-mssql\bin\ and libodb-mssql\lib\ directories, respectively. -Similarly, the 64-bit DLLs and import libraries are placed into -libodb-mssql\bin64\ and libodb-mssql\lib64\. The Release versions of -the import libraries are named odb-mssql.lib and the Debug versions -are named odb-mssql-d.lib. - -To configure Visual Studio to automatically locate the libodb-mssql -headers, DLLs, and import libraries, add the following paths to your -VC++ Directories: - -Win32: - - Include: ...\libodb-mssql - Library: ...\libodb-mssql\lib - Executable: ...\libodb-mssql\bin - -x64: - - Include: ...\libodb-mssql - Library: ...\libodb-mssql\lib64 - Executable: ...\libodb-mssql\bin64 diff --git a/INSTALL-GIT b/INSTALL-GIT deleted file mode 100644 index f917af5..0000000 --- a/INSTALL-GIT +++ /dev/null @@ -1,78 +0,0 @@ -The following instructions describe how to work with the source code that was -checked out from the git repository. - -The major difference between using a released source code package and source -code from the repository is that the former does not contain autotools-based -makefiles or Visual Studio project files. Instead, it contains templates for -these files as well as its own, custom build system. This build system is -used for development as well as to automatically generate the autotools and -Visual Studio files. - -This file describes how to use this build system to build the package as well -as to create a release-ready source distribution which contains the autotools -build system and Visual Studio project files. - - -Prerequisites -============= - -Besides the prerequisites listed in the INSTALL file, you will need the -following additional packages: - - - GNU bash >= 2.0.0 http://www.gnu.org/software/bash/ - - GNU make >= 3.81 http://www.gnu.org/software/make/ - - build >= latest http://www.codesynthesis.com/projects/build/ - -If you are planning to create the source code distributions, then you will -also need the following packages: - - - GNU m4 >= 1.4.0 http://www.gnu.org/software/m4/ - - GNU sed >= 4.0.0 http://www.gnu.org/software/sed/ - - tofrodos >= 1.7.0 http://www.thefreecountry.com/tofrodos/ - -As we as the GNU autotools: - - - GNU libtool >= 2.2.6b http://www.gnu.org/software/libtool/ - - GNU autoconf >= 2.67 http://www.gnu.org/software/autoconf/ - - GNU automake >= 1.11.1 http://www.gnu.org/software/automake/ - -Any reasonably up to date GNU/Linux installation would normally have all of -the above packages already present, except for build and maybe tofrodos. - - -Configuring and Building -======================== - -To build the source code simply run make in the root directory of the package. -The first time you run make, the build process will also configure the -package by asking you several questions. On the subsequent runs, make will -only rebuild what has changed. - -To run the automated test suite (if any), run 'make test'. To clean the object -files, executables, etc., run 'make clean'. To de-configure the package (that -is, to remove configuration files in addition to objects, executables, etc.), -run 'make disfigure'. - - -Creating Distribution -===================== - -To create the source code distribution, use the dist make target as well as -the dist_prefix variable to specify the directory where the distribution files -should be placed. For example: - -make dist dist_prefix=/tmp/package-1.1.0 - -Once the distribution files are ready, change to the distribution directory -and run the bootstrap script to bootstrap the autotools build system, for -example: - -cd /tmp/package-1.1.0 -./bootsrap - -To create the source code archives, use the autotools build system. First -configuring the package (see the INSTALL file for more information on this -step) and then use the dist target to make the archives, for example: - -./configure -make dist diff --git a/LICENSE b/LICENSE deleted file mode 100644 index c5effce..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2009-2024 Code Synthesis Tools CC. - -Permission is granted to use, copy, modify, and distribute this -program under the ODB Non-Commercial Use and Evaluation License -(NCUEL) as published by Code Synthesis Tools CC. - -For more information on ODB licensing as well as for answers to -some of the common licensing questions, visit the ODB License -page: - -http://www.codesynthesis.com/products/odb/license.xhtml - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -ODB Non-Commercial Use and Evaluation License for details. - -You should have received a copy of the ODB Non-Commercial Use and -Evaluation License (normally located in the NCUEL file that is -accompanying the distribution); if not, contact Code Synthesis -Tools CC at info@codesynthesis.com. diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index c458cc7..0000000 --- a/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -# file : Makefile.am -# license : ODB NCUEL; see accompanying LICENSE file - -SUBDIRS = __path__(dirs) -dist_doc_DATA = __file__(docs) -EXTRA_DIST = __file__(extra_dist) -ACLOCAL_AMFLAGS = -I m4 - -pkgconfigdir = @pkgconfigdir@ -pkgconfig_DATA= libodb-mssql.pc diff --git a/NCUEL b/NCUEL deleted file mode 100644 index e8e179c..0000000 --- a/NCUEL +++ /dev/null @@ -1,294 +0,0 @@ - ODB NON-COMMERCIAL USE AND EVALUATION LICENSE (NCUEL) - -INTENT - -The intent of this license is to allow you to use ODB with commercial -databases, such as Oracle, Microsoft SQL Server, IBM DB/2, etc., free -of charge non-commercially or for evaluation. - -Furthermore, if a commercial database has a free edition, often called -express edition, such as Oracle Express, Microsoft SQL Server Express, -IBM DB/2 Express-C, etc., that can be used for commercial purposes free -of charge, then this license allows you to use ODB with such an edition -for commercial purposes also free of charge. - -Note also that the development of an application that will be used for -commercial purposes constitutes a commercial use and is not allowed, -except with a free edition of a commercial database. However, this -license allows you to evaluate ODB; that is, to use the Software for -a reasonable period for the purpose of determining its suitability for -a particular application as well as to conduct exploratory development -or proof-of-concept prototyping. - -Finally, any application that uses ODB under this license, whether non- -commercially, for evaluation, or commercially with a free edition of a -database, is subject to the terms and conditions similar to that of the -GPL version 2. In particular, this means that if and when you distribute -your application, you are required to also release its source code. - -If you have any questions concerning this License, please contact us at: -info@codesynthesis.com. - -LEGAL TERMS AND CONDITIONS - -This Code Synthesis Tools CC Non-Commercial Use and Evaluation License -Agreement for ODB Software ("License") is a legal agreement between you, -the Licensee, (either an individual or a single entity) and Code -Synthesis Tools CC ("Code Synthesis") for non-commercially using, -copying, distributing and modifying the Software and any work derived -from the Software, as defined hereinbelow. Any commercial use, except -as expressly provided in Section 2.1, is subject to a different license. - -By using, modifying, or distributing the Software or any work derived -from the Software, Licensee indicates acceptance of this License and -agrees to be bound by all its terms and conditions for using, copying, -distributing, or modifying the Software and works derived from the -Software. If Licensee is agreeing to this License on behalf of an entity -other than an individual person, Licensee represents that Licensee is -binding and have the right to bind the entity to the terms and conditions -of this agreement. - -These terms and conditions only apply to the ODB components that are -explicitly licensed under this License (normally ODB runtime libraries -for commercial databases). Other ODB components may be licensed under -other licenses and are not affected in any way by the terms and -conditions found in this License. Similarly, ODB components licensed -under this License are not affected by the terms and conditions found -in other licenses. If you are using several ODB components that are -licensed under different licenses, you must comply with the terms and -conditions of each such license. - -No rights are granted to the Software except as expressly set forth -herein. Nothing other than this License grants Licensee permission to -use, copy, distribute or modify the Software or any work derived from -the Software. Licensee may not use, copy, distribute or modify the -Software or any work derived from the Software except as expressly -provided under this License. If Licensee does not accept the terms and -conditions of this License, Licensee shall not use, copy, distribute -or modify the Software. - -In consideration for Licensee's forbearance of commercial use of the -Software, except as expressly provided in Section 2.1, Code Synthesis -grants Licensee non-exclusive, royalty-free and without fees rights -as expressly provided herein. - -1. DEFINITIONS. - -A "commercial database" is a database product that has associated -fees and/or royalties payable for production and/or commercial use -of the database product. Commercial databases include, but are not -limited to, Oracle, Microsoft SQL Server, and IBM DB/2. - -A "free edition of a commercial database" is a special, limited edition -of a commercial database, often called express edition, that does not -require fees and/or royalties for production and/or commercial use. -Free editions of commercial databases include, but are not limited to, -Oracle Express, Microsoft SQL Server Express, and IBM DB/2 Express-C. - -The "Software" is one of the ODB runtime libraries for one of the -commercial databases, including, but not limited to, demo programs, -associated media and printed materials, and any included "on-line" -documentation. - -A "work derived from the Software" is any derivative work as defined -in the copyright law of the nation or state where rights to the work -derived from the Software are exercisable; that is to say, a program -which is linked with or otherwise incorporates the ODB runtime library -or a translation, improvement, enhancement, extension or other -modification of the Software which has sufficient originality to -qualify in such a nation or state as a copyrightable work is a work -derived from the Software. - -To "use" means to execute (i.e. run) the Software. - -To "copy" means to create one or more copies of the Software. - -To "distribute" means to broadcast, publish, transfer, post, upload, -download or otherwise disseminate in any medium to any third party. - -To "modify" means to create a work derived from the Software. - -To "evaluate" means to use the Software for a reasonable period for -the purpose of determining its suitability for a particular application -as well as to conduct exploratory development or proof-of-concept -prototyping. - -A "commercial use" is: - -(1) the use of the Software or any work derived from the Software in -connection with, for or in aid of the generation of revenue, such as -in the conduct of Licensee's daily business operations; or - -(2) any copying, distribution or modification of the Software or any -work derived from the Software to any party where payment or other -consideration is made in connection with such copying, distribution or -modification, whether directly (as in payment for a copy of the -Software) or indirectly (including but not limited to payment for some -good or service related to the Software, or payment for some product -or service that includes a copy of the Software "without charge"). -However, the following actions which involve payment do not in and -of themselves constitute a commercial use: - -(a) posting the Software on a public access information storage and -retrieval service for which a fee is received for retrieving -information (such as an on-line service), provided that the fee is not -content-dependent. Such fees which are not content dependent include, -but are not limited to, fees which are based solely on the storage -capacity required to store the information, and fees which are based -solely on the time required to transfer the information from/to the -public access information storage and retrieval service; and - -(b) distributing the Software on a CD-ROM, provided that the Software -is reproduced entirely and verbatim on such CD-ROM, and provided further -that all information on such CD-ROM may be distributed in a manner which -does not constitute a commercial use. - -2. GRANT OF LICENSE. - -2.1. LICENSE TO USE. -Licensee may use the Software provided that such use does not constitute -a commercial use. - -Licensee may also use the Software commercially with a free edition of a -commercial database, if such an edition is available. If Licensee -distributes works derived from the Software and such works may be used -commercially by third parties, Licensee must cause such commercial use -to be limited to a free edition of a commercial database. - -2.2. LICENSE TO EVALUATE. -Licensee may evaluation the Software for commercial use. - -2.3. LICENSE TO COPY AND DISTRIBUTE. -Licensee may copy and distribute literal (i.e., verbatim) copies of the -Software as Licensee receives it throughout the world, in any medium, -provided that Licensee distributes an unmodified, easily-readable copy -of this License with the Software, and provided further that such -distribution does not constitute a commercial use. - -2.4. LICENSE TO CREATE WORKS DERIVED FROM THE SOFTWARE. -Licensee may create works derived from the Software, provided that any -such work derived from the Software carries prominent notices stating -both the manner in which Licensee has created a work derived from the -Software (for example, notices stating that the work derived from the -Software is linked with or otherwise incorporates the ODB runtime -library, or notices stating that the work derived from the Software -is an enhancement to the Software which Licensee has created) and the -date any such work derived from the Software was created. - -2.5. LICENSE TO COPY AND DISTRIBUTE WORKS DERIVED FROM THE SOFTWARE. -Licensee may copy and distribute works derived from the Software -throughout the world, provided that Licensee distributes an -unmodified, easily-readable copy of this License with such works -derived from the Software, and provided further that such distribution -does not constitute a commercial use. Licensee must cause any work -derived from the Software that Licensee distributes to be licensed as -a whole and at no charge to all third parties under the terms of this -License or another free/open source license that does not restrict any -rights of any third party that would have been granted should such work -have been licensed under this License. - -Any work derived from the Software must be accompanied by the complete -corresponding machine-readable source code of such work derived from -the Software, delivered on a medium customarily used for software -interchange. The source code for the work derived from the Software -means the preferred form of the work derived from the Software for -making modifications to it. For an executable work derived from the -Software, complete source code means all of the source code for all -modules of the work derived from the Software, all associated -interface definition files and all scripts used to control compilation -and installation of all or any part of the work derived from the -Software. However, the source code delivered need not include anything -that is normally distributed, in either source code or binary (object- -code) form, with major components (including but not limited to -compilers, linkers, and kernels) of the operating system on which the -executable work derived from the Software runs, unless that component -itself accompanies the executable code of the work derived from the -Software. - -Furthermore, if the executable code or object code of the work derived -from the Software may be copied from a designated place, and if the -source code of the work derived from the Software may be copied from -the same place, then the work derived from the Software shall be -construed as accompanied by the complete corresponding machine-readable -source code of such work derived from the Software, even though third -parties are not compelled to copy the source code along with the -executable code or object code. - -If the work derived from the Software normally reads commands -interactively when run, Licensee must cause the work derived from the -Software, at each time it commences operation, to print or display an -announcement including either a notice consisting of the verbatim -warranty and liability provisions of this License, or a notice that -Licensee, and not Code Synthesis provides a warranty. - -Licensee may not impose any further restrictions on the exercise of -the rights granted herein by any recipient of any work derived from -the Software. - -3. RESTRICTIONS. - -Licensee acknowledges that the Software is protected by copyright laws -and international copyright treaties, as well as other intellectual -property laws and treaties. The Software is licensed, not sold. All -title and copyrights in and to the Software are owned exclusively by -Code Synthesis. - -Licensee may not sublicense, assign or transfer this License, the -Software or any work derived from the Software except as permitted by -this License. - -Licensee is expressly prohibited from using, copying, distributing, -studying the source code, or otherwise examining the Software for -the purpose of reverse engineering or duplicating its functionality -(unless enforcement of this restrictions is prohibited by applicable -law). - -4. LIMITED WARRANTY. - -4.1 NO WARRANTIES. -CODE SYNTHESIS EXPRESSLY DISCLAIMS ANY WARRANTY FOR THE SOFTWARE. THE -SOFTWARE IS PROVIDED TO LICENSEE "AS IS," WITHOUT WARRANTY OF ANY KIND, -EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE USE, -QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH LICENSEE. SHOULD THE -SOFTWARE PROVE DEFECTIVE, LICENSEE ASSUMES THE COST OF ALL NECESSARY -SERVICING, REPAIR OR CORRECTION. - -4.2. NO LIABILITY FOR DAMAGES. -IN NO EVENT WILL CODE SYNTHESIS, OR ANY OTHER PARTY WHO MAY COPY, -DISTRIBUTE OR MODIFY THE SOFTWARE AS PERMITTED HEREIN, BE LIABLE FOR -ANY GENERAL, DIRECT, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL -DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF -BUSINESS PROFITS, BUSINESS INTERRUPTION, INACCURATE INFORMATION, LOSS -OF INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OR -INABILITY TO USE THE SOFTWARE, EVEN IF CODE SYNTHESIS OR SUCH OTHER -PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -5. TERMINATION. - -Any violation or any attempt to violate any of the terms and conditions -of this License will automatically terminate Licensee's rights under -this License. Licensee further agrees upon such termination to cease -any and all using, copying, distributing and modifying of the Software -and any work derived from the Software, and further to destroy any and -all of Licensee's copies of the Software and any work derived from the -Software. - -However, parties who have received copies of the Software or copies of -any work derived from the Software, or rights, from Licensee under this -License will not have their licenses terminated so long as such parties -remain in full compliance with this License. - -6. LICENSE SCOPE AND MODIFICATION. - -This License sets forth the entire agreement between Licensee and Code -Synthesis and supersedes all prior agreements and understandings between -the parties relating to the subject matter hereof. None of the terms of -this License may be waived or modified except as expressly agreed in -writing by both Licensee and Code Synthesis. - -7. SEVERABILITY. - -Should any provision of this License be declared void or unenforceable, -the validity of the remaining provisions shall not be affected thereby. diff --git a/NEWS b/NEWS deleted file mode 100644 index 72d0f8b..0000000 --- a/NEWS +++ /dev/null @@ -1 +0,0 @@ -See the common NEWS file in the ODB compiler package. diff --git a/README b/README deleted file mode 100644 index 21671b7..0000000 --- a/README +++ /dev/null @@ -1,20 +0,0 @@ -ODB is an object-relational mapping (ORM) system for C++. It provides -tools, APIs, and library support that allow you to persist C++ objects -to a relational database (RDBMS) without having to deal with tables, -columns, or SQL and without manually writing any of the mapping code. -For more information see: - -http://www.codesynthesis.com/products/odb/ - -This package contains the Microsoft SQL Server ODB runtime library. -Every application that includes code generated for the SQL Server -database will need to link to this library. - -See the NEWS file for the user-visible changes from the previous release. - -See the LICENSE file for distribution conditions. - -See the INSTALL file for prerequisites and installation instructions. - -Send questions, bug reports, or any other feedback to the -odb-users@codesynthesis.com mailing list. diff --git a/README-GIT b/README-GIT deleted file mode 100644 index 173c041..0000000 --- a/README-GIT +++ /dev/null @@ -1,5 +0,0 @@ -The checked out odb/mssql/version-build2.hxx will be overwritten during the -build process but these changes should be ignored. To do this automatically, -run: - -git update-index --assume-unchanged odb/mssql/version-build2.hxx diff --git a/bootstrap b/bootstrap deleted file mode 100755 index ff29551..0000000 --- a/bootstrap +++ /dev/null @@ -1,16 +0,0 @@ -#! /bin/sh - -# file : bootstrap -# license : ODB NCUEL; see accompanying LICENSE file - -# -# Bootstrap the automake build system. -# - -rm -f config.cache - -if test ! -d m4; then - mkdir m4 -fi - -autoreconf --install diff --git a/build/.gitignore b/build/.gitignore deleted file mode 100644 index 4a730a3..0000000 --- a/build/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -config.build -root/ -bootstrap/ diff --git a/build/bootstrap.build b/build/bootstrap.build deleted file mode 100644 index fddf8ad..0000000 --- a/build/bootstrap.build +++ /dev/null @@ -1,10 +0,0 @@ -# file : build/bootstrap.build -# license : ODB NCUEL; see accompanying LICENSE file - -project = libodb-mssql - -using version -using config -using dist -using test -using install diff --git a/build/bootstrap.make b/build/bootstrap.make deleted file mode 100644 index 37282c6..0000000 --- a/build/bootstrap.make +++ /dev/null @@ -1,70 +0,0 @@ -# file : build/bootstrap.make -# license : ODB NCUEL; see accompanying LICENSE file - -project_name := libodb-mssql - -# First try to include the bundled bootstrap.make if it exist. If that -# fails, let make search for the external bootstrap.make. -# -build := build-0.3 - --include $(dir $(lastword $(MAKEFILE_LIST)))../../$(build)/bootstrap.make - -ifeq ($(patsubst %build/bootstrap.make,,$(lastword $(MAKEFILE_LIST))),) -include $(build)/bootstrap.make -endif - - -# Aliases -# -.PHONY: $(out_base)/ \ - $(out_base)/.test \ - $(out_base)/.dist \ - $(out_base)/.clean - -ifdef %interactive% - -.PHONY: test dist clean - -test: $(out_base)/.test -dist: $(out_base)/.dist -clean: $(out_base)/.clean - -ifneq ($(filter $(.DEFAULT_GOAL),test dist clean),) -.DEFAULT_GOAL := -endif - -endif - -# Make sure the distribution prefix is set if the goal is dist. -# -ifneq ($(filter $(MAKECMDGOALS),dist),) -ifeq ($(dist_prefix),) -$(error dist_prefix is not set) -endif -endif - -# If we don't have dependency auto-generation then we need to manually -# make sure that generated files are generated before C++ file are -# compiler. To do this we make the object files ($2) depend in order- -# only on generated files ($3). -# -ifeq ($(cxx_id),generic) - -define include-dep -$(if $2,$(eval $2: | $3)) -endef - -else - -define include-dep -$(call -include,$1) -endef - -endif - -# Don't include dependency info for certain targets. -# -ifneq ($(filter $(MAKECMDGOALS),clean disfigure dist),) -include-dep = -endif diff --git a/build/export.build b/build/export.build deleted file mode 100644 index ad90a96..0000000 --- a/build/export.build +++ /dev/null @@ -1,9 +0,0 @@ -# file : build/export.build -# license : ODB NCUEL; see accompanying LICENSE file - -$out_root/ -{ - include odb/mssql/ -} - -export $out_root/odb/mssql/lib{odb-mssql} diff --git a/build/export/libodb-mssql/stub.make b/build/export/libodb-mssql/stub.make deleted file mode 100644 index 5083ed2..0000000 --- a/build/export/libodb-mssql/stub.make +++ /dev/null @@ -1,8 +0,0 @@ -# file : build/export/libodb-mssql/stub.make -# license : ODB NCUEL; see accompanying LICENSE file - -$(call include-once,$(src_root)/odb/mssql/makefile,$(out_root)) - -$(call export,\ - l: $(out_root)/odb/mssql/odb-mssql.l,\ - cpp-options: $(out_root)/odb/mssql/odb-mssql.l.cpp-options) diff --git a/build/import/cli/cli-cxx.make b/build/import/cli/cli-cxx.make deleted file mode 100644 index 9bdf238..0000000 --- a/build/import/cli/cli-cxx.make +++ /dev/null @@ -1,47 +0,0 @@ -# file : build/import/cli/cli-cxx.make -# license : MIT; see accompanying LICENSE file - -# Here we are operating in the importing project's space, not in -# cli's. -# - -# Get the C++ file extensions. -# -$(call include,$(bld_root)/cxx/configuration-static.make) - -cli_pattern := \ -$(out_base)/%.$(cxx_s_suffix) \ -$(out_base)/%.$(cxx_h_suffix) \ -$(out_base)/%.$(cxx_i_suffix) - -$(cli_pattern): cli_options := \ ---hxx-suffix .$(cxx_h_suffix) \ ---ixx-suffix .$(cxx_i_suffix) \ ---cxx-suffix .$(cxx_s_suffix) - -.PRECIOUS: $(cli_pattern) - -ifeq ($(out_base),$(src_base)) - -$(cli_pattern): $(src_base)/%.cli - $(call message,cli $<,$(cli) $(cli_options) --output-dir $(dir $@) $<) - -else - -$(cli_pattern): $(src_base)/%.cli | $$(dir $$@). - $(call message,cli $<,$(cli) $(cli_options) --output-dir $(dir $@) $<) - -$(cli_pattern): $(out_base)/%.cli | $$(dir $$@). - $(call message,cli $<,$(cli) $(cli_options) --output-dir $(dir $@) $<) -endif - -.PHONY: $(out_base)/%.cxx.cli.clean - -$(out_base)/%.cxx.cli.clean: cxx_s_suffix := $(cxx_s_suffix) -$(out_base)/%.cxx.cli.clean: cxx_h_suffix := $(cxx_h_suffix) -$(out_base)/%.cxx.cli.clean: cxx_i_suffix := $(cxx_i_suffix) - -$(out_base)/%.cxx.cli.clean: - $(call message,rm $$1,rm -f $$1,$(@:.cxx.cli.clean=.$(cxx_s_suffix))) - $(call message,rm $$1,rm -f $$1,$(@:.cxx.cli.clean=.$(cxx_h_suffix))) - $(call message,rm $$1,rm -f $$1,$(@:.cxx.cli.clean=.$(cxx_i_suffix))) diff --git a/build/import/cli/configuration-rules.make b/build/import/cli/configuration-rules.make deleted file mode 100644 index 6355000..0000000 --- a/build/import/cli/configuration-rules.make +++ /dev/null @@ -1,13 +0,0 @@ -# file : build/import/cli/configuration-rules.make -# license : MIT; see accompanying LICENSE file - -$(dcf_root)/import/cli/configuration-dynamic.make: | $(dcf_root)/import/cli/. - $(call message,,$(scf_root)/import/cli/configure $@) - -ifndef %foreign% - -$(dcf_root)/.disfigure:: - $(call message,rm $(dcf_root)/import/cli/configuration-dynamic.make,\ -rm -f $(dcf_root)/import/cli/configuration-dynamic.make) - -endif diff --git a/build/import/cli/configure b/build/import/cli/configure deleted file mode 100755 index 2a1fde4..0000000 --- a/build/import/cli/configure +++ /dev/null @@ -1,53 +0,0 @@ -#! /usr/bin/env bash - -# file : build/import/cli/configure -# license : MIT; see accompanying LICENSE file - - -# $1 - out file -# -# bld_root - build root -# project_name - project name -# - -source $bld_root/dialog.bash - - -$echo -$echo "Configuring external dependency on 'cli' for '$project_name'." -$echo - -$echo -$echo "Would you like to configure dependency on the installed " -$echo "version of 'cli' as opposed to the development build?" -$echo - -installed=`read_y_n y` - -path= - -if [ "$installed" = "n" ]; then - -$echo -$echo "Please enter the src_root for 'cli'." -$echo - -src_root=`read_path --directory --exist` - -$echo -$echo "Please enter the out_root for 'cli'." -$eche - -out_root=`read_path --directory $src_root` - -fi - -echo cli_installed := $installed >$1 - -if [ "$installed" = "n" ]; then - -echo src_root := $src_root >>$1 -echo scf_root := \$\(src_root\)/build >>$1 -echo out_root := $out_root >>$1 - -fi diff --git a/build/import/cli/stub.make b/build/import/cli/stub.make deleted file mode 100644 index 741b371..0000000 --- a/build/import/cli/stub.make +++ /dev/null @@ -1,28 +0,0 @@ -# file : build/import/cli/stub.make -# license : MIT; see accompanying LICENSE file - -$(call include-once,$(scf_root)/import/cli/configuration-rules.make,$(dcf_root)) - -cli_installed := - -$(call -include,$(dcf_root)/import/cli/configuration-dynamic.make) - -ifdef cli_installed - -ifeq ($(cli_installed),y) - -$(call export,cli: cli,cli-rules: $(scf_root)/import/cli/cli-cxx.make) - -else - -# Include export stub. -# -$(call include,$(scf_root)/export/cli/stub.make) - -endif - -else - -.NOTPARALLEL: - -endif diff --git a/build/import/libodb-mssql/configuration-rules.make b/build/import/libodb-mssql/configuration-rules.make deleted file mode 100644 index 5fd58bc..0000000 --- a/build/import/libodb-mssql/configuration-rules.make +++ /dev/null @@ -1,13 +0,0 @@ -# file : build/import/libodb-mssql/configuration-rules.make -# license : ODB NCUEL; see accompanying LICENSE file - -$(dcf_root)/import/libodb-mssql/configuration-dynamic.make: | $(dcf_root)/import/libodb-mssql/. - $(call message,,$(scf_root)/import/libodb-mssql/configure $@) - -ifndef %foreign% - -$(dcf_root)/.disfigure:: - $(call message,rm $(dcf_root)/import/libodb-mssql/configuration-dynamic.make,\ -rm -f $(dcf_root)/import/libodb-mssql/configuration-dynamic.make) - -endif diff --git a/build/import/libodb-mssql/configure b/build/import/libodb-mssql/configure deleted file mode 100755 index 5e2a28a..0000000 --- a/build/import/libodb-mssql/configure +++ /dev/null @@ -1,53 +0,0 @@ -#! /usr/bin/env bash - -# file : build/import/libodb-mssql/configure -# license : ODB NCUEL; see accompanying LICENSE file - - -# $1 - out file -# -# bld_root - build root -# project_name - project name -# - -source $bld_root/dialog.bash - - -$echo -$echo "Configuring external dependency on 'libodb-mssql' for '$project_name'." -$echo - -$echo -$echo "Would you like to configure dependency on the installed version" -$echo "of 'libodb-mssql' as opposed to the development build?" -$echo - -installed=`read_y_n y` - -path= - -if [ "$installed" = "n" ]; then - -$echo -$echo "Please enter the src_root for 'libodb-mssql'." -$echo - -src_root=`read_path --directory --exist` - -$echo -$echo "Please enter the out_root for 'libodb-mssql'." -$echo - -out_root=`read_path --directory $src_root` - -fi - -echo libodb_mssql_installed := $installed >$1 - -if [ "$installed" = "n" ]; then - -echo src_root := $src_root >>$1 -echo scf_root := \$\(src_root\)/build >>$1 -echo out_root := $out_root >>$1 - -fi diff --git a/build/import/libodb-mssql/stub.make b/build/import/libodb-mssql/stub.make deleted file mode 100644 index eebf11a..0000000 --- a/build/import/libodb-mssql/stub.make +++ /dev/null @@ -1,28 +0,0 @@ -# file : build/import/libodb-mssql/stub.make -# license : ODB NCUEL; see accompanying LICENSE file - -$(call include-once,$(scf_root)/import/libodb-mssql/configuration-rules.make,$(dcf_root)) - -libodb_mssql_installed := - -$(call -include,$(dcf_root)/import/libodb-mssql/configuration-dynamic.make) - -ifdef libodb_mssql_installed - -ifeq ($(libodb_mssql_installed),y) - -$(call export,l: -lodb-mssql -lodb -lodbc,cpp-options: ) - -else - -# Include export stub. -# -$(call include,$(scf_root)/export/libodb-mssql/stub.make) - -endif - -else - -.NOTPARALLEL: - -endif diff --git a/build/import/libodb/configuration-rules.make b/build/import/libodb/configuration-rules.make deleted file mode 100644 index 340c418..0000000 --- a/build/import/libodb/configuration-rules.make +++ /dev/null @@ -1,13 +0,0 @@ -# file : build/import/libodb/configuration-rules.make -# license : GNU GPL v2; see accompanying LICENSE file - -$(dcf_root)/import/libodb/configuration-dynamic.make: | $(dcf_root)/import/libodb/. - $(call message,,$(scf_root)/import/libodb/configure $@) - -ifndef %foreign% - -$(dcf_root)/.disfigure:: - $(call message,rm $(dcf_root)/import/libodb/configuration-dynamic.make,\ -rm -f $(dcf_root)/import/libodb/configuration-dynamic.make) - -endif diff --git a/build/import/libodb/configure b/build/import/libodb/configure deleted file mode 100755 index 261a202..0000000 --- a/build/import/libodb/configure +++ /dev/null @@ -1,53 +0,0 @@ -#! /usr/bin/env bash - -# file : build/import/libodb/configure -# license : GNU GPL v2; see accompanying LICENSE file - - -# $1 - out file -# -# bld_root - build root -# project_name - project name -# - -source $bld_root/dialog.bash - - -$echo -$echo "Configuring external dependency on 'libodb' for '$project_name'." -$echo - -$echo -$echo "Would you like to configure dependency on the installed " -$echo "version of 'libodb' as opposed to the development build?" -$echo - -installed=`read_y_n y` - -path= - -if [ "$installed" = "n" ]; then - -$echo -$echo "Please enter the src_root for 'libodb'." -$echo - -src_root=`read_path --directory --exist` - -$echo -$echo "Please enter the out_root for 'libodb'." -$echo - -out_root=`read_path --directory $src_root` - -fi - -echo libodb_installed := $installed >$1 - -if [ "$installed" = "n" ]; then - -echo src_root := $src_root >>$1 -echo scf_root := \$\(src_root\)/build >>$1 -echo out_root := $out_root >>$1 - -fi diff --git a/build/import/libodb/stub.make b/build/import/libodb/stub.make deleted file mode 100644 index 04dc786..0000000 --- a/build/import/libodb/stub.make +++ /dev/null @@ -1,28 +0,0 @@ -# file : build/import/libodb/stub.make -# license : GNU GPL v2; see accompanying LICENSE file - -$(call include-once,$(scf_root)/import/libodb/configuration-rules.make,$(dcf_root)) - -libodb_installed := - -$(call -include,$(dcf_root)/import/libodb/configuration-dynamic.make) - -ifdef libodb_installed - -ifeq ($(libodb_installed),y) - -$(call export,l: -lodb,cpp-options: ) - -else - -# Include export stub. -# -$(call include,$(scf_root)/export/libodb/stub.make) - -endif - -else - -.NOTPARALLEL: - -endif diff --git a/build/import/libodbc/configuration-rules.make b/build/import/libodbc/configuration-rules.make deleted file mode 100644 index eae32fc..0000000 --- a/build/import/libodbc/configuration-rules.make +++ /dev/null @@ -1,13 +0,0 @@ -# file : build/import/libodbc/configuration-rules.make -# license : GNU GPL v2; see accompanying LICENSE file - -$(dcf_root)/import/libodbc/configuration-dynamic.make: | $(dcf_root)/import/libodbc/. - $(call message,,$(scf_root)/import/libodbc/configure $@) - -ifndef %foreign% - -disfigure:: - $(call message,rm $(dcf_root)/import/libodbc/configuration-dynamic.make,\ -rm -f $(dcf_root)/import/libodbc/configuration-dynamic.make) - -endif diff --git a/build/import/libodbc/configure b/build/import/libodbc/configure deleted file mode 100755 index 7438010..0000000 --- a/build/import/libodbc/configure +++ /dev/null @@ -1,28 +0,0 @@ -#! /usr/bin/env bash - -# file : build/import/libodbc/configure -# license : GNU GPL v2; see accompanying LICENSE file - - -# $1 - out config file -# -# bld_root - build root -# project_name - project name -# - -source $bld_root/dialog.bash - -$echo -$echo "Configuring external dependency on 'ODBC library' for '$project_name'." -$echo - -$echo -$echo "Please select the driver manager you would like to use:" -$echo -$echo "(1) Windows ODBC" -$echo "(2) unixODBC" -$echo - -manager=`read_option "windows unix" "unix"` - -echo libodbc_manager := $manager >$1 diff --git a/build/import/libodbc/stub.make b/build/import/libodbc/stub.make deleted file mode 100644 index 6e98af4..0000000 --- a/build/import/libodbc/stub.make +++ /dev/null @@ -1,22 +0,0 @@ -# file : build/import/libodbc/stub.make -# license : GNU GPL v2; see accompanying LICENSE file - -$(call include-once,$(scf_root)/import/libodbc/configuration-rules.make,$(dcf_root)) - -libodbc_manager := - -$(call -include,$(dcf_root)/import/libodbc/configuration-dynamic.make) - -ifdef libodbc_manager - -ifeq ($(libodbc_manager),windows) -$(call export,l: -lodbc32,cpp-options: ) -else -$(call export,l: -lodbc,cpp-options: ) -endif - -else - -.NOTPARALLEL: - -endif diff --git a/build/import/libodbc/version b/build/import/libodbc/version deleted file mode 100644 index 6e8bf73..0000000 --- a/build/import/libodbc/version +++ /dev/null @@ -1 +0,0 @@ -0.1.0 diff --git a/build/root.build b/build/root.build deleted file mode 100644 index 794e083..0000000 --- a/build/root.build +++ /dev/null @@ -1,19 +0,0 @@ -# file : build/root.build -# license : ODB NCUEL; see accompanying LICENSE file - -config [bool] config.libodb_mssql.develop ?= false - -cxx.std = latest - -using cxx - -hxx{*}: extension = hxx -ixx{*}: extension = ixx -txx{*}: extension = txx -cxx{*}: extension = cxx - -if ($cxx.target.system == 'win32-msvc') - cxx.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS - -if ($cxx.class == 'msvc') - cxx.coptions += /wd4251 /wd4275 /wd4800 diff --git a/buildfile b/buildfile deleted file mode 100644 index d7329c2..0000000 --- a/buildfile +++ /dev/null @@ -1,9 +0,0 @@ -# file : buildfile -# license : ODB NCUEL; see accompanying LICENSE file - -./: {*/ -build/ -m4/} doc{INSTALL NEWS README} legal{NCUEL LICENSE} manifest - -# Don't install tests or the INSTALL file. -# -tests/: install = false -doc{INSTALL}@./: install = false diff --git a/configure.ac b/configure.ac deleted file mode 100644 index eafb6bd..0000000 --- a/configure.ac +++ /dev/null @@ -1,57 +0,0 @@ -# file : configure.ac -# license : ODB NCUEL; see accompanying LICENSE file - -AC_PREREQ(2.60) -AC_INIT([libodb-mssql], [__value__(version)], [odb-users@codesynthesis.com]) -AC_CONFIG_AUX_DIR([config]) -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_SRCDIR([odb/mssql/version.hxx]) - -AM_INIT_AUTOMAKE([-Wall -Werror foreign nostdinc subdir-objects dist-bzip2 dist-zip tar-ustar]) -m4_equote()[m4_ifdef]m4_dquote()([AM_PROG_AR], [AM_PROG_AR]) # Required by automake 1.12. - -LT_INIT([win32-dll]) - -AC_CANONICAL_HOST - -# Check for C++ compiler and use it to compile the tests. -# -AC_PROG_CXX -AC_LANG(C++) - -# Create the libtool executable so that we can use it in further tests. -# -LT_OUTPUT - -# Check for threads. -# -THREADS - -# Check for ODBC. -# -LIBODBC( - [], - [AC_MSG_ERROR([ODBC is not found; consider using CPPFLAGS/LDFLAGS to specify its location])]) - -# Check for libodb. -# -LIBODB([],[AC_MSG_ERROR([libodb is not found; consider using --with-libodb=DIR])]) - -# Define LIBODB_MSSQL_STATIC_LIB if we are build static library on certain -# platforms. -# -STATIC_LIB([LIBODB_MSSQL_STATIC_LIB], [Static library interface.]) - -# Allow the user to specify the pkgconfig directory. -# -PKGCONFIG - -# Check if we should disable rpath. -# -DISABLE_RPATH - -# Output. -# -AC_CONFIG_HEADERS([odb/mssql/config.h odb/mssql/details/config.h]) -AC_CONFIG_FILES([__path__(config_files)]) -AC_OUTPUT diff --git a/libodb-mssql-vc10.sln b/libodb-mssql-vc10.sln deleted file mode 100644 index 40a3bc3..0000000 --- a/libodb-mssql-vc10.sln +++ /dev/null @@ -1,26 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{C1335C92-809F-41A7-877A-4A0193D974D3}") = "libodb-mssql", "odb\mssql\libodb-mssql-vc10.vcxproj", "{E1AB8673-9D52-4984-AF83-BCB5BC97BB13}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|Win32.ActiveCfg = Debug|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|Win32.Build.0 = Debug|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|x64.ActiveCfg = Debug|x64 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|x64.Build.0 = Debug|x64 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|Win32.ActiveCfg = Release|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|Win32.Build.0 = Release|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|x64.ActiveCfg = Release|x64 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/libodb-mssql-vc11.sln b/libodb-mssql-vc11.sln deleted file mode 100644 index ea1f7de..0000000 --- a/libodb-mssql-vc11.sln +++ /dev/null @@ -1,26 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{C1335C92-809F-41A7-877A-4A0193D974D3}") = "libodb-mssql", "odb\mssql\libodb-mssql-vc11.vcxproj", "{E1AB8673-9D52-4984-AF83-BCB5BC97BB13}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|Win32.ActiveCfg = Debug|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|Win32.Build.0 = Debug|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|x64.ActiveCfg = Debug|x64 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|x64.Build.0 = Debug|x64 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|Win32.ActiveCfg = Release|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|Win32.Build.0 = Release|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|x64.ActiveCfg = Release|x64 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/libodb-mssql-vc12.sln b/libodb-mssql-vc12.sln deleted file mode 100644 index 5746219..0000000 --- a/libodb-mssql-vc12.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{C1335C92-809F-41A7-877A-4A0193D974D3}") = "libodb-mssql", "odb\mssql\libodb-mssql-vc12.vcxproj", "{E1AB8673-9D52-4984-AF83-BCB5BC97BB13}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|Win32.ActiveCfg = Debug|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|Win32.Build.0 = Debug|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|x64.ActiveCfg = Debug|x64 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Debug|x64.Build.0 = Debug|x64 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|Win32.ActiveCfg = Release|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|Win32.Build.0 = Release|Win32 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|x64.ActiveCfg = Release|x64 - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/libodb-mssql-vc8.sln b/libodb-mssql-vc8.sln deleted file mode 100644 index 345b4c4..0000000 --- a/libodb-mssql-vc8.sln +++ /dev/null @@ -1,26 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{C3AD7165-4D15-4E93-BE2A-D2B237C7A33C}") = "libodb-mssql", "odb\mssql\libodb-mssql-vc8.vcproj", "{43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Debug|Win32.ActiveCfg = Debug|Win32 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Debug|Win32.Build.0 = Debug|Win32 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Debug|x64.ActiveCfg = Debug|x64 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Debug|x64.Build.0 = Debug|x64 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Release|Win32.ActiveCfg = Release|Win32 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Release|Win32.Build.0 = Release|Win32 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Release|x64.ActiveCfg = Release|x64 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/libodb-mssql-vc9.sln b/libodb-mssql-vc9.sln deleted file mode 100644 index 7f10611..0000000 --- a/libodb-mssql-vc9.sln +++ /dev/null @@ -1,26 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{C3AD7165-4D15-4E93-BE2A-D2B237C7A33C}") = "libodb-mssql", "odb\mssql\libodb-mssql-vc9.vcproj", "{43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Debug|Win32.ActiveCfg = Debug|Win32 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Debug|Win32.Build.0 = Debug|Win32 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Debug|x64.ActiveCfg = Debug|x64 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Debug|x64.Build.0 = Debug|x64 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Release|Win32.ActiveCfg = Release|Win32 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Release|Win32.Build.0 = Release|Win32 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Release|x64.ActiveCfg = Release|x64 - {43BDD7EE-1811-4C49-8ED6-76E2B0222AF0}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/libodb-mssql.pc.in b/libodb-mssql.pc.in deleted file mode 100644 index 0b858c2..0000000 --- a/libodb-mssql.pc.in +++ /dev/null @@ -1,14 +0,0 @@ -# file : libodb-mssql.pc.in -# license : ODB NCUEL; see accompanying LICENSE file - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libodb-mssql -Description: Object-relational mapping (ORM) system for C++, Microsoft SQL Server runtime library -URL: http://www.codesynthesis.com/products/odb/ -Version: @VERSION@ -Libs: -L${libdir} -lodb-mssql -Cflags: -I${includedir} diff --git a/libodb-mssql/.gitignore b/libodb-mssql/.gitignore new file mode 100644 index 0000000..1c363a0 --- /dev/null +++ b/libodb-mssql/.gitignore @@ -0,0 +1,25 @@ +# Compiler/linker output. +# +*.d +*.t +*.i +*.i.* +*.ii +*.ii.* +*.o +*.obj +*.gcm +*.pcm +*.ifc +*.so +*.dylib +*.dll +*.a +*.lib +*.exp +*.pdb +*.ilk +*.exe +*.exe.dlls/ +*.exe.manifest +*.pc diff --git a/libodb-mssql/INSTALL b/libodb-mssql/INSTALL new file mode 100644 index 0000000..b6e2be5 --- /dev/null +++ b/libodb-mssql/INSTALL @@ -0,0 +1,6 @@ +The easiest way to build this package is with the bpkg package manager: + +$ bpkg build libodb-mssql + +But if you don't want to use the package manager, then you can also build it +manually using the standard build2 build system. diff --git a/libodb-mssql/LICENSE b/libodb-mssql/LICENSE new file mode 100644 index 0000000..c5effce --- /dev/null +++ b/libodb-mssql/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2009-2024 Code Synthesis Tools CC. + +Permission is granted to use, copy, modify, and distribute this +program under the ODB Non-Commercial Use and Evaluation License +(NCUEL) as published by Code Synthesis Tools CC. + +For more information on ODB licensing as well as for answers to +some of the common licensing questions, visit the ODB License +page: + +http://www.codesynthesis.com/products/odb/license.xhtml + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +ODB Non-Commercial Use and Evaluation License for details. + +You should have received a copy of the ODB Non-Commercial Use and +Evaluation License (normally located in the NCUEL file that is +accompanying the distribution); if not, contact Code Synthesis +Tools CC at info@codesynthesis.com. diff --git a/libodb-mssql/NCUEL b/libodb-mssql/NCUEL new file mode 100644 index 0000000..e8e179c --- /dev/null +++ b/libodb-mssql/NCUEL @@ -0,0 +1,294 @@ + ODB NON-COMMERCIAL USE AND EVALUATION LICENSE (NCUEL) + +INTENT + +The intent of this license is to allow you to use ODB with commercial +databases, such as Oracle, Microsoft SQL Server, IBM DB/2, etc., free +of charge non-commercially or for evaluation. + +Furthermore, if a commercial database has a free edition, often called +express edition, such as Oracle Express, Microsoft SQL Server Express, +IBM DB/2 Express-C, etc., that can be used for commercial purposes free +of charge, then this license allows you to use ODB with such an edition +for commercial purposes also free of charge. + +Note also that the development of an application that will be used for +commercial purposes constitutes a commercial use and is not allowed, +except with a free edition of a commercial database. However, this +license allows you to evaluate ODB; that is, to use the Software for +a reasonable period for the purpose of determining its suitability for +a particular application as well as to conduct exploratory development +or proof-of-concept prototyping. + +Finally, any application that uses ODB under this license, whether non- +commercially, for evaluation, or commercially with a free edition of a +database, is subject to the terms and conditions similar to that of the +GPL version 2. In particular, this means that if and when you distribute +your application, you are required to also release its source code. + +If you have any questions concerning this License, please contact us at: +info@codesynthesis.com. + +LEGAL TERMS AND CONDITIONS + +This Code Synthesis Tools CC Non-Commercial Use and Evaluation License +Agreement for ODB Software ("License") is a legal agreement between you, +the Licensee, (either an individual or a single entity) and Code +Synthesis Tools CC ("Code Synthesis") for non-commercially using, +copying, distributing and modifying the Software and any work derived +from the Software, as defined hereinbelow. Any commercial use, except +as expressly provided in Section 2.1, is subject to a different license. + +By using, modifying, or distributing the Software or any work derived +from the Software, Licensee indicates acceptance of this License and +agrees to be bound by all its terms and conditions for using, copying, +distributing, or modifying the Software and works derived from the +Software. If Licensee is agreeing to this License on behalf of an entity +other than an individual person, Licensee represents that Licensee is +binding and have the right to bind the entity to the terms and conditions +of this agreement. + +These terms and conditions only apply to the ODB components that are +explicitly licensed under this License (normally ODB runtime libraries +for commercial databases). Other ODB components may be licensed under +other licenses and are not affected in any way by the terms and +conditions found in this License. Similarly, ODB components licensed +under this License are not affected by the terms and conditions found +in other licenses. If you are using several ODB components that are +licensed under different licenses, you must comply with the terms and +conditions of each such license. + +No rights are granted to the Software except as expressly set forth +herein. Nothing other than this License grants Licensee permission to +use, copy, distribute or modify the Software or any work derived from +the Software. Licensee may not use, copy, distribute or modify the +Software or any work derived from the Software except as expressly +provided under this License. If Licensee does not accept the terms and +conditions of this License, Licensee shall not use, copy, distribute +or modify the Software. + +In consideration for Licensee's forbearance of commercial use of the +Software, except as expressly provided in Section 2.1, Code Synthesis +grants Licensee non-exclusive, royalty-free and without fees rights +as expressly provided herein. + +1. DEFINITIONS. + +A "commercial database" is a database product that has associated +fees and/or royalties payable for production and/or commercial use +of the database product. Commercial databases include, but are not +limited to, Oracle, Microsoft SQL Server, and IBM DB/2. + +A "free edition of a commercial database" is a special, limited edition +of a commercial database, often called express edition, that does not +require fees and/or royalties for production and/or commercial use. +Free editions of commercial databases include, but are not limited to, +Oracle Express, Microsoft SQL Server Express, and IBM DB/2 Express-C. + +The "Software" is one of the ODB runtime libraries for one of the +commercial databases, including, but not limited to, demo programs, +associated media and printed materials, and any included "on-line" +documentation. + +A "work derived from the Software" is any derivative work as defined +in the copyright law of the nation or state where rights to the work +derived from the Software are exercisable; that is to say, a program +which is linked with or otherwise incorporates the ODB runtime library +or a translation, improvement, enhancement, extension or other +modification of the Software which has sufficient originality to +qualify in such a nation or state as a copyrightable work is a work +derived from the Software. + +To "use" means to execute (i.e. run) the Software. + +To "copy" means to create one or more copies of the Software. + +To "distribute" means to broadcast, publish, transfer, post, upload, +download or otherwise disseminate in any medium to any third party. + +To "modify" means to create a work derived from the Software. + +To "evaluate" means to use the Software for a reasonable period for +the purpose of determining its suitability for a particular application +as well as to conduct exploratory development or proof-of-concept +prototyping. + +A "commercial use" is: + +(1) the use of the Software or any work derived from the Software in +connection with, for or in aid of the generation of revenue, such as +in the conduct of Licensee's daily business operations; or + +(2) any copying, distribution or modification of the Software or any +work derived from the Software to any party where payment or other +consideration is made in connection with such copying, distribution or +modification, whether directly (as in payment for a copy of the +Software) or indirectly (including but not limited to payment for some +good or service related to the Software, or payment for some product +or service that includes a copy of the Software "without charge"). +However, the following actions which involve payment do not in and +of themselves constitute a commercial use: + +(a) posting the Software on a public access information storage and +retrieval service for which a fee is received for retrieving +information (such as an on-line service), provided that the fee is not +content-dependent. Such fees which are not content dependent include, +but are not limited to, fees which are based solely on the storage +capacity required to store the information, and fees which are based +solely on the time required to transfer the information from/to the +public access information storage and retrieval service; and + +(b) distributing the Software on a CD-ROM, provided that the Software +is reproduced entirely and verbatim on such CD-ROM, and provided further +that all information on such CD-ROM may be distributed in a manner which +does not constitute a commercial use. + +2. GRANT OF LICENSE. + +2.1. LICENSE TO USE. +Licensee may use the Software provided that such use does not constitute +a commercial use. + +Licensee may also use the Software commercially with a free edition of a +commercial database, if such an edition is available. If Licensee +distributes works derived from the Software and such works may be used +commercially by third parties, Licensee must cause such commercial use +to be limited to a free edition of a commercial database. + +2.2. LICENSE TO EVALUATE. +Licensee may evaluation the Software for commercial use. + +2.3. LICENSE TO COPY AND DISTRIBUTE. +Licensee may copy and distribute literal (i.e., verbatim) copies of the +Software as Licensee receives it throughout the world, in any medium, +provided that Licensee distributes an unmodified, easily-readable copy +of this License with the Software, and provided further that such +distribution does not constitute a commercial use. + +2.4. LICENSE TO CREATE WORKS DERIVED FROM THE SOFTWARE. +Licensee may create works derived from the Software, provided that any +such work derived from the Software carries prominent notices stating +both the manner in which Licensee has created a work derived from the +Software (for example, notices stating that the work derived from the +Software is linked with or otherwise incorporates the ODB runtime +library, or notices stating that the work derived from the Software +is an enhancement to the Software which Licensee has created) and the +date any such work derived from the Software was created. + +2.5. LICENSE TO COPY AND DISTRIBUTE WORKS DERIVED FROM THE SOFTWARE. +Licensee may copy and distribute works derived from the Software +throughout the world, provided that Licensee distributes an +unmodified, easily-readable copy of this License with such works +derived from the Software, and provided further that such distribution +does not constitute a commercial use. Licensee must cause any work +derived from the Software that Licensee distributes to be licensed as +a whole and at no charge to all third parties under the terms of this +License or another free/open source license that does not restrict any +rights of any third party that would have been granted should such work +have been licensed under this License. + +Any work derived from the Software must be accompanied by the complete +corresponding machine-readable source code of such work derived from +the Software, delivered on a medium customarily used for software +interchange. The source code for the work derived from the Software +means the preferred form of the work derived from the Software for +making modifications to it. For an executable work derived from the +Software, complete source code means all of the source code for all +modules of the work derived from the Software, all associated +interface definition files and all scripts used to control compilation +and installation of all or any part of the work derived from the +Software. However, the source code delivered need not include anything +that is normally distributed, in either source code or binary (object- +code) form, with major components (including but not limited to +compilers, linkers, and kernels) of the operating system on which the +executable work derived from the Software runs, unless that component +itself accompanies the executable code of the work derived from the +Software. + +Furthermore, if the executable code or object code of the work derived +from the Software may be copied from a designated place, and if the +source code of the work derived from the Software may be copied from +the same place, then the work derived from the Software shall be +construed as accompanied by the complete corresponding machine-readable +source code of such work derived from the Software, even though third +parties are not compelled to copy the source code along with the +executable code or object code. + +If the work derived from the Software normally reads commands +interactively when run, Licensee must cause the work derived from the +Software, at each time it commences operation, to print or display an +announcement including either a notice consisting of the verbatim +warranty and liability provisions of this License, or a notice that +Licensee, and not Code Synthesis provides a warranty. + +Licensee may not impose any further restrictions on the exercise of +the rights granted herein by any recipient of any work derived from +the Software. + +3. RESTRICTIONS. + +Licensee acknowledges that the Software is protected by copyright laws +and international copyright treaties, as well as other intellectual +property laws and treaties. The Software is licensed, not sold. All +title and copyrights in and to the Software are owned exclusively by +Code Synthesis. + +Licensee may not sublicense, assign or transfer this License, the +Software or any work derived from the Software except as permitted by +this License. + +Licensee is expressly prohibited from using, copying, distributing, +studying the source code, or otherwise examining the Software for +the purpose of reverse engineering or duplicating its functionality +(unless enforcement of this restrictions is prohibited by applicable +law). + +4. LIMITED WARRANTY. + +4.1 NO WARRANTIES. +CODE SYNTHESIS EXPRESSLY DISCLAIMS ANY WARRANTY FOR THE SOFTWARE. THE +SOFTWARE IS PROVIDED TO LICENSEE "AS IS," WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE USE, +QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH LICENSEE. SHOULD THE +SOFTWARE PROVE DEFECTIVE, LICENSEE ASSUMES THE COST OF ALL NECESSARY +SERVICING, REPAIR OR CORRECTION. + +4.2. NO LIABILITY FOR DAMAGES. +IN NO EVENT WILL CODE SYNTHESIS, OR ANY OTHER PARTY WHO MAY COPY, +DISTRIBUTE OR MODIFY THE SOFTWARE AS PERMITTED HEREIN, BE LIABLE FOR +ANY GENERAL, DIRECT, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL +DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF +BUSINESS PROFITS, BUSINESS INTERRUPTION, INACCURATE INFORMATION, LOSS +OF INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OR +INABILITY TO USE THE SOFTWARE, EVEN IF CODE SYNTHESIS OR SUCH OTHER +PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +5. TERMINATION. + +Any violation or any attempt to violate any of the terms and conditions +of this License will automatically terminate Licensee's rights under +this License. Licensee further agrees upon such termination to cease +any and all using, copying, distributing and modifying of the Software +and any work derived from the Software, and further to destroy any and +all of Licensee's copies of the Software and any work derived from the +Software. + +However, parties who have received copies of the Software or copies of +any work derived from the Software, or rights, from Licensee under this +License will not have their licenses terminated so long as such parties +remain in full compliance with this License. + +6. LICENSE SCOPE AND MODIFICATION. + +This License sets forth the entire agreement between Licensee and Code +Synthesis and supersedes all prior agreements and understandings between +the parties relating to the subject matter hereof. None of the terms of +this License may be waived or modified except as expressly agreed in +writing by both Licensee and Code Synthesis. + +7. SEVERABILITY. + +Should any provision of this License be declared void or unenforceable, +the validity of the remaining provisions shall not be affected thereby. diff --git a/libodb-mssql/README b/libodb-mssql/README new file mode 100644 index 0000000..21671b7 --- /dev/null +++ b/libodb-mssql/README @@ -0,0 +1,20 @@ +ODB is an object-relational mapping (ORM) system for C++. It provides +tools, APIs, and library support that allow you to persist C++ objects +to a relational database (RDBMS) without having to deal with tables, +columns, or SQL and without manually writing any of the mapping code. +For more information see: + +http://www.codesynthesis.com/products/odb/ + +This package contains the Microsoft SQL Server ODB runtime library. +Every application that includes code generated for the SQL Server +database will need to link to this library. + +See the NEWS file for the user-visible changes from the previous release. + +See the LICENSE file for distribution conditions. + +See the INSTALL file for prerequisites and installation instructions. + +Send questions, bug reports, or any other feedback to the +odb-users@codesynthesis.com mailing list. diff --git a/libodb-mssql/build/.gitignore b/libodb-mssql/build/.gitignore new file mode 100644 index 0000000..4a730a3 --- /dev/null +++ b/libodb-mssql/build/.gitignore @@ -0,0 +1,3 @@ +config.build +root/ +bootstrap/ diff --git a/libodb-mssql/build/bootstrap.build b/libodb-mssql/build/bootstrap.build new file mode 100644 index 0000000..fddf8ad --- /dev/null +++ b/libodb-mssql/build/bootstrap.build @@ -0,0 +1,10 @@ +# file : build/bootstrap.build +# license : ODB NCUEL; see accompanying LICENSE file + +project = libodb-mssql + +using version +using config +using dist +using test +using install diff --git a/libodb-mssql/build/export.build b/libodb-mssql/build/export.build new file mode 100644 index 0000000..ad90a96 --- /dev/null +++ b/libodb-mssql/build/export.build @@ -0,0 +1,9 @@ +# file : build/export.build +# license : ODB NCUEL; see accompanying LICENSE file + +$out_root/ +{ + include odb/mssql/ +} + +export $out_root/odb/mssql/lib{odb-mssql} diff --git a/libodb-mssql/build/root.build b/libodb-mssql/build/root.build new file mode 100644 index 0000000..794e083 --- /dev/null +++ b/libodb-mssql/build/root.build @@ -0,0 +1,19 @@ +# file : build/root.build +# license : ODB NCUEL; see accompanying LICENSE file + +config [bool] config.libodb_mssql.develop ?= false + +cxx.std = latest + +using cxx + +hxx{*}: extension = hxx +ixx{*}: extension = ixx +txx{*}: extension = txx +cxx{*}: extension = cxx + +if ($cxx.target.system == 'win32-msvc') + cxx.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS + +if ($cxx.class == 'msvc') + cxx.coptions += /wd4251 /wd4275 /wd4800 diff --git a/libodb-mssql/buildfile b/libodb-mssql/buildfile new file mode 100644 index 0000000..db1aceb --- /dev/null +++ b/libodb-mssql/buildfile @@ -0,0 +1,9 @@ +# file : buildfile +# license : ODB NCUEL; see accompanying LICENSE file + +./: {*/ -build/} doc{INSTALL NEWS README} legal{NCUEL LICENSE} manifest + +# Don't install tests or the INSTALL file. +# +tests/: install = false +doc{INSTALL}@./: install = false diff --git a/libodb-mssql/manifest b/libodb-mssql/manifest new file mode 100644 index 0000000..68e5a84 --- /dev/null +++ b/libodb-mssql/manifest @@ -0,0 +1,23 @@ +: 1 +name: libodb-mssql +version: 2.5.0-b.26.z +project: odb +summary: Microsoft SQL Server ODB runtime library +license: other: ODB NCUEL ; Non-Commercial Use and Evaluation License. +license: other: proprietary ; Not free/open source. +topics: C++, ORM, Microsoft SQL Server, SQL +description-file: README +changes-file: NEWS +url: https://www.codesynthesis.com/products/odb/ +doc-url: https://www.codesynthesis.com/products/odb/doc/manual.xhtml +src-url: https://git.codesynthesis.com/cgit/odb/libodb-mssql/ +email: odb-users@codesynthesis.com +build-warning-email: odb-builds@codesynthesis.com +builds: windows ; Requires not yet packaged libunixodbc (unixODBC). +requires: c++11 +# @@ DEP +#requires: ? libunixodbc ; Only on UNIX. +depends: * build2 >= 0.16.0- +depends: * bpkg >= 0.16.0- +depends: libodb [2.5.0-b.26.1 2.5.0-b.27) +depends: * cli ^1.2.0- ? ($config.libodb_mssql.develop) diff --git a/libodb-mssql/odb/mssql/auto-handle.cxx b/libodb-mssql/odb/mssql/auto-handle.cxx new file mode 100644 index 0000000..ca42040 --- /dev/null +++ b/libodb-mssql/odb/mssql/auto-handle.cxx @@ -0,0 +1,17 @@ +// file : odb/mssql/auto-handle.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include +#include + +namespace odb +{ + namespace mssql + { + void + free_handle (SQLHANDLE h, SQLSMALLINT htype) + { + SQLFreeHandle (htype, h); + } + } +} diff --git a/libodb-mssql/odb/mssql/auto-handle.hxx b/libodb-mssql/odb/mssql/auto-handle.hxx new file mode 100644 index 0000000..f6934e4 --- /dev/null +++ b/libodb-mssql/odb/mssql/auto-handle.hxx @@ -0,0 +1,88 @@ +// file : odb/mssql/auto-handle.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_AUTO_HANDLE_HXX +#define ODB_MSSQL_AUTO_HANDLE_HXX + +#include + +#include // ODB_CXX11 + +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + LIBODB_MSSQL_EXPORT void + free_handle (SQLHANDLE, SQLSMALLINT htype); + + template + class auto_handle + { + public: + auto_handle (SQLHANDLE h = 0) + : h_ (h) + { + } + + ~auto_handle () + { + if (h_ != 0) + free_handle (h_, htype); + } + + operator SQLHANDLE () const + { + return h_; + } + + SQLHANDLE + get () const + { + return h_; + } + + SQLHANDLE + release () + { + SQLHANDLE h (h_); + h_ = 0; + return h; + } + + void + reset (SQLHANDLE h = 0) + { + if (h_ != 0) + free_handle (h_, htype); + + h_ = h; + } + +#ifdef ODB_CXX11 + auto_handle (auto_handle&& ah) noexcept: h_ (ah.release ()) {} + auto_handle& operator= (auto_handle&& ah) noexcept + { + if (this != &ah) + reset (ah.release ()); + return *this; + } +#endif + + private: + auto_handle (const auto_handle&); + auto_handle& operator= (const auto_handle&); + + private: + SQLHANDLE h_; + }; + } +} + +#include + +#endif // ODB_MSSQL_AUTO_HANDLE_HXX diff --git a/libodb-mssql/odb/mssql/binding.hxx b/libodb-mssql/odb/mssql/binding.hxx new file mode 100644 index 0000000..c7d1bd8 --- /dev/null +++ b/libodb-mssql/odb/mssql/binding.hxx @@ -0,0 +1,65 @@ +// file : odb/mssql/binding.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_BINDING_HXX +#define ODB_MSSQL_BINDING_HXX + +#include + +#include // std::size_t + +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class LIBODB_MSSQL_EXPORT binding + { + public: + typedef mssql::bind bind_type; + typedef mssql::change_callback change_callback_type; + + binding () + : bind (0), count (0), version (0), + batch (0), skip (0), status (0), + change_callback (0) {} + + binding (bind_type* b, std::size_t n) + : bind (b), count (n), version (0), + batch (1), skip (0), status (0), + change_callback (0) + { + } + + binding (bind_type* b, std::size_t n, + std::size_t bt, std::size_t s, SQLUSMALLINT* st) + : bind (b), count (n), version (0), + batch (bt), skip (s), status (st), + change_callback (0) + { + } + + bind_type* bind; + std::size_t count; + std::size_t version; + + std::size_t batch; + std::size_t skip; + SQLUSMALLINT* status; // Batch status array. + + change_callback_type* change_callback; + + private: + binding (const binding&); + binding& operator= (const binding&); + }; + } +} + +#include + +#endif // ODB_MSSQL_BINDING_HXX diff --git a/libodb-mssql/odb/mssql/buildfile b/libodb-mssql/odb/mssql/buildfile new file mode 100644 index 0000000..5a99ebc --- /dev/null +++ b/libodb-mssql/odb/mssql/buildfile @@ -0,0 +1,165 @@ +# file : odb/mssql/buildfile +# license : ODB NCUEL; see accompanying LICENSE file + +define cli: file +cli{*}: extension = cli + +import int_libs = libodb%lib{odb} + +# On Windows ODBC is a pre-installed system library so we pass it to the +# linker directly +# +imp_libs = + +if ($cc.target.class != 'windows') + import imp_libs = libunixodbc%lib{odbc} + +lib{odb-mssql}: {hxx ixx txx cxx}{* -version-build2} {hxx}{version-build2} \ + details/{hxx ixx txx cxx}{* -options} \ + details/build2/{h}{*} \ + $imp_libs $int_libs + +# Include the generated version header into the distribution (so that we don't +# pick up an installed one) and don't remove it when cleaning in src (so that +# clean results in a state identical to distributed). +# +hxx{version-build2}: in{version-build2} $src_root/manifest +hxx{version-build2}: +{ + dist = true + clean = ($src_root != $out_root) +} + +# Build options. +# +cxx.poptions =+ "-I$out_root" "-I$src_root" -DLIBODB_MSSQL_BUILD2 + +obja{*}: cxx.poptions += -DLIBODB_MSSQL_STATIC_BUILD +objs{*}: cxx.poptions += -DLIBODB_MSSQL_SHARED_BUILD + +if ($cc.target.class == 'windows') + cxx.libs += ($cxx.target.system == "mingw32" ? -lodbc32 : odbc32.lib) + +# Export options. +# +lib{odb-mssql}: +{ + cxx.export.poptions = "-I$out_root" "-I$src_root" -DLIBODB_MSSQL_BUILD2 + cxx.export.libs = $int_libs +} + +liba{odb-mssql}: cxx.export.poptions += -DLIBODB_MSSQL_STATIC +libs{odb-mssql}: cxx.export.poptions += -DLIBODB_MSSQL_SHARED + +# For pre-releases use the complete version to make sure they cannot be used +# in place of another pre-release or the final version. See the version module +# for details on the version.* variable values. +# +if $version.pre_release + lib{odb-mssql}: bin.lib.version = @"-$version.project_id" +else + lib{odb-mssql}: bin.lib.version = @"-$version.major.$version.minor" + +develop = $config.libodb_mssql.develop + +## Consumption build ($develop == false). +# + +# Use pregenerated versions in the consumption build. +# +lib{odb-mssql}: details/pregenerated/{hxx ixx cxx}{**}: include = (!$develop) + +if! $develop + cxx.poptions =+ "-I($src_base/details/pregenerated)" # Note: must come first. + +# Don't install pregenerated headers since they are only used internally in +# the database implementation (also below). +# +details/pregenerated/{hxx ixx}{*}: install = false + +# Distribute pregenerated versions only in the consumption build. +# +details/pregenerated/{hxx ixx cxx}{*}: dist = (!$develop) + +# +## + +## Development build ($develop == true). +# + +lib{odb-mssql}: details/{hxx ixx cxx}{options}: include = $develop + +if $develop + import! [metadata] cli = cli%exe{cli} + +# In the development build distribute regenerated {hxx ixx cxx}{options}, +# remapping their locations to the paths of the pregenerated versions (which +# are only distributed in the consumption build; see above). This way we make +# sure that the distributed files are always up-to-date. +# +
: details/cli{options} $cli +{ + install = false + dist = ($develop ? pregenerated/odb/mssql/details/ : false) + + # Symlink the generated code in src for convenience of development. + # + backlink = true +} +% +if $develop +{{ + options = --include-with-brackets --include-prefix odb/mssql/details \ + --guard-prefix LIBODB_MSSQL_DETAILS --generate-file-scanner \ + --cli-namespace odb::mssql::details::cli --long-usage \ + --generate-specifier --no-combined-flags + + $cli $options -o $out_base/details/ $path($<[0]) + + # If the result differs from the pregenerated version, copy it over. + # + d = [dir_path] $src_base/details/pregenerated/odb/mssql/details/ + + if diff $d/options.hxx $path($>[0]) >- && \ + diff $d/options.ixx $path($>[1]) >- && \ + diff $d/options.cxx $path($>[2]) >- + exit + end + + cp $path($>[0]) $d/options.hxx + cp $path($>[1]) $d/options.ixx + cp $path($>[2]) $d/options.cxx +}} + +# Install into the odb/mssql/ subdirectory of, say, /usr/include/ +# recreating subdirectories. +# +install_include = [dir_path] include/odb/mssql/ + +{hxx ixx txx}{*}: +{ + install = $install_include + install.subdirs = true +} + +# We want these to be picked up whether LIBODB_MSSQL_BUILD2 is defined or not. +# +hxx{version}@./: install = false +hxx{version-build2}: install = $install_include/version.hxx +hxx{version-build2-stub}@./: install = $install_include/version-build2.hxx + +details/build2/ +{ + h{*}: install = false + + if ($cxx.target.system == 'win32-msvc') + { + h{config-vc}@./: install = $install_include/details/ + h{config-vc-stub}@./: install = $install_include/details/build2/config-vc.h + } + else + { + h{config}@./: install = $install_include/details/ + h{config-stub}@./: install = $install_include/details/build2/config.h + } +} diff --git a/libodb-mssql/odb/mssql/connection-factory.cxx b/libodb-mssql/odb/mssql/connection-factory.cxx new file mode 100644 index 0000000..f673b92 --- /dev/null +++ b/libodb-mssql/odb/mssql/connection-factory.cxx @@ -0,0 +1,159 @@ +// file : odb/mssql/connection-factory.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include +#include + +#include + +using namespace std; + +namespace odb +{ + using namespace details; + + namespace mssql + { + // new_connection_factory + // + connection_ptr new_connection_factory:: + connect () + { + return connection_ptr (new (shared) connection (*this)); + } + + // connection_pool_factory + // + connection_pool_factory::pooled_connection_ptr connection_pool_factory:: + create () + { + return pooled_connection_ptr (new (shared) pooled_connection (*this)); + } + + connection_pool_factory:: + ~connection_pool_factory () + { + // Wait for all the connections currently in use to return to + // the pool. + // + lock l (mutex_); + while (in_use_ != 0) + { + waiters_++; + cond_.wait (l); + waiters_--; + } + } + + connection_ptr connection_pool_factory:: + connect () + { + lock l (mutex_); + + while (true) + { + // See if we have a spare connection. + // + if (connections_.size () != 0) + { + shared_ptr c (connections_.back ()); + connections_.pop_back (); + + c->callback_ = &c->cb_; + in_use_++; + return c; + } + + // See if we can create a new one. + // + if (max_ == 0 || in_use_ < max_) + { + shared_ptr c (create ()); + c->callback_ = &c->cb_; + in_use_++; + return c; + } + + // Wait until someone releases a connection. + // + waiters_++; + cond_.wait (l); + waiters_--; + } + } + + void connection_pool_factory:: + database (database_type& db) + { + bool first (db_ == 0); + + connection_factory::database (db); + + if (!first) + return; + + if (min_ > 0) + { + connections_.reserve (min_); + + for(size_t i (0); i < min_; ++i) + connections_.push_back (create ()); + } + } + + bool connection_pool_factory:: + release (pooled_connection* c) + { + c->callback_ = 0; + + lock l (mutex_); + + // Determine if we need to keep or free this connection. + // + bool keep (!c->failed () && + (waiters_ != 0 || + min_ == 0 || + (connections_.size () + in_use_ <= min_))); + + in_use_--; + + if (keep) + { + connections_.push_back (pooled_connection_ptr (inc_ref (c))); + connections_.back ()->recycle (); + } + + if (waiters_ != 0) + cond_.signal (); + + return !keep; + } + + // + // connection_pool_factory::pooled_connection + // + + connection_pool_factory::pooled_connection:: + pooled_connection (connection_pool_factory& f) + : connection (f) + { + cb_.arg = this; + cb_.zero_counter = &zero_counter; + } + + connection_pool_factory::pooled_connection:: + pooled_connection (connection_pool_factory& f, SQLHDBC handle) + : connection (f, handle) + { + cb_.arg = this; + cb_.zero_counter = &zero_counter; + } + + bool connection_pool_factory::pooled_connection:: + zero_counter (void* arg) + { + pooled_connection* c (static_cast (arg)); + return static_cast (c->factory_).release (c); + } + } +} diff --git a/libodb-mssql/odb/mssql/connection-factory.hxx b/libodb-mssql/odb/mssql/connection-factory.hxx new file mode 100644 index 0000000..14861a5 --- /dev/null +++ b/libodb-mssql/odb/mssql/connection-factory.hxx @@ -0,0 +1,134 @@ +// file : odb/mssql/connection-factory.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_CONNECTION_FACTORY_HXX +#define ODB_MSSQL_CONNECTION_FACTORY_HXX + +#include + +#include +#include // std::size_t +#include + +#include +#include +#include + +#include +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class LIBODB_MSSQL_EXPORT new_connection_factory: public connection_factory + { + public: + new_connection_factory () {} + + virtual connection_ptr + connect (); + + private: + new_connection_factory (const new_connection_factory&); + new_connection_factory& operator= (const new_connection_factory&); + }; + + class LIBODB_MSSQL_EXPORT connection_pool_factory: + public connection_factory + { + public: + // The max_connections argument specifies the maximum number of + // concurrent connections this pool will maintain. If this value + // is 0 then the pool will create a new connection every time all + // of the existing connections are in use. + // + // The min_connections argument specifies the minimum number of + // connections that should be maintained by the pool. If the + // number of connections maintained by the pool exceeds this + // number and there are no active waiters for a new connection, + // then the pool will release the excess connections. If this + // value is 0 then the pool will maintain all the connections + // that were ever created. + // + connection_pool_factory (std::size_t max_connections = 0, + std::size_t min_connections = 0) + : max_ (max_connections), + min_ (min_connections), + in_use_ (0), + waiters_ (0), + cond_ (mutex_) + { + // max_connections == 0 means unlimited. + // + assert (max_connections == 0 || max_connections >= min_connections); + } + + virtual connection_ptr + connect (); + + virtual void + database (database_type&); + + virtual + ~connection_pool_factory (); + + private: + connection_pool_factory (const connection_pool_factory&); + connection_pool_factory& operator= (const connection_pool_factory&); + + protected: + class LIBODB_MSSQL_EXPORT pooled_connection: public connection + { + public: + pooled_connection (connection_pool_factory&); + pooled_connection (connection_pool_factory&, SQLHDBC); + + private: + static bool + zero_counter (void*); + + private: + friend class connection_pool_factory; + + shared_base::refcount_callback cb_; + }; + + friend class pooled_connection; + + typedef details::shared_ptr pooled_connection_ptr; + typedef std::vector connections; + + // This function is called whenever the pool needs to create a new + // connection. + // + virtual pooled_connection_ptr + create (); + + protected: + // Return true if the connection should be deleted, false otherwise. + // + bool + release (pooled_connection*); + + protected: + const std::size_t max_; + const std::size_t min_; + + std::size_t in_use_; // Number of connections currently in use. + std::size_t waiters_; // Number of threads waiting for a connection. + + connections connections_; + + details::mutex mutex_; + details::condition cond_; + }; + } +} + +#include + +#endif // ODB_MSSQL_CONNECTION_FACTORY_HXX diff --git a/libodb-mssql/odb/mssql/connection.cxx b/libodb-mssql/odb/mssql/connection.cxx new file mode 100644 index 0000000..5181fab --- /dev/null +++ b/libodb-mssql/odb/mssql/connection.cxx @@ -0,0 +1,287 @@ +// file : odb/mssql/connection.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include +#include //intptr_t + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace odb +{ + namespace mssql + { + static const intptr_t transaction_isolation_map[] = + { + SQL_TXN_READ_UNCOMMITTED, + SQL_TXN_READ_COMMITTED, + SQL_TXN_REPEATABLE_READ, + SQL_TXN_SS_SNAPSHOT, + SQL_TXN_SERIALIZABLE + }; + + connection:: + connection (connection_factory& cf) + : odb::connection (cf), + state_ (state_disconnected), + statement_cache_ (new statement_cache_type (*this)), + long_data_buffer_ (0) + { + SQLRETURN r; + + database_type& db (database ()); + + // Allocate the connection handle. + // + { + SQLHANDLE h; + r = SQLAllocHandle (SQL_HANDLE_DBC, db.environment (), &h); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, db.environment (), SQL_HANDLE_ENV); + + handle_.reset (h); + } + + // Set the manual commit mode. + // + r = SQLSetConnectAttrA (handle_, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER) SQL_AUTOCOMMIT_OFF, + 0); + + if (!SQL_SUCCEEDED (r)) + // Still use the handle version of translate_error since there + // is no connection yet. + // + translate_error (r, handle_, SQL_HANDLE_DBC); + + // Enable Multiple Active Result Sets (MARS). + // + r = SQLSetConnectAttrA (handle_, + SQL_COPT_SS_MARS_ENABLED, + (SQLPOINTER) SQL_MARS_ENABLED_YES, + SQL_IS_UINTEGER); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, handle_, SQL_HANDLE_DBC); + + // Set transaction isolation level. + // + transaction_isolation ti (db.transaction_isolation ()); + switch (ti) + { + case isolation_read_committed: + { + break; // SQL Server default. + } + case isolation_read_uncommitted: + case isolation_repeatable_read: + case isolation_serializable: + { + r = SQLSetConnectAttrA (handle_, + SQL_ATTR_TXN_ISOLATION, + (SQLPOINTER) transaction_isolation_map[ti], + 0); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, handle_, SQL_HANDLE_DBC); + break; + } + case isolation_snapshot: + { + r = SQLSetConnectAttrA (handle_, + SQL_COPT_SS_TXN_ISOLATION, + (SQLPOINTER) transaction_isolation_map[ti], + SQL_IS_INTEGER); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, handle_, SQL_HANDLE_DBC); + break; + } + } + + // Connect. + // + { + SQLSMALLINT out_conn_str_size; + r = SQLDriverConnectA (handle_, + 0, // Parent window handle. + (SQLCHAR*) db.connect_string ().c_str (), + SQL_NTS, + 0, // Output connection string buffer. + 0, // Size of output connection string buffer. + &out_conn_str_size, + SQL_DRIVER_NOPROMPT); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, handle_, SQL_HANDLE_DBC); + + state_ = state_connected; + } + + // If an exception is thrown after this line, we will not disconnect + // the connection. + // + } + + connection:: + connection (connection_factory& cf, SQLHDBC handle) + : odb::connection (cf), + handle_ (handle), + state_ (state_connected), + statement_cache_ (new statement_cache_type (*this)), + long_data_buffer_ (0) + { + } + + connection:: + ~connection () + { + // Deallocate prepared statements before we close the connection. + // + recycle (); + clear_prepared_map (); + statement_cache_.reset (); + direct_stmt_.reset (); + + if (state_ != state_disconnected) + SQLDisconnect (handle_); // Ignore any errors. + } + + transaction_impl* connection:: + begin () + { + return new transaction_impl (connection_ptr (inc_ref (this))); + } + + unsigned long long connection:: + execute (const char* s, std::size_t n) + { + { + odb::tracer* t; + if ((t = transaction_tracer ()) || + (t = tracer ()) || + (t = database ().tracer ())) + { + string str (s, n); + t->execute (*this, str.c_str ()); + } + } + + SQLRETURN r; + + // Allocate the statement if necessary. + // + if (direct_stmt_ == 0) + { + SQLHANDLE h; + r = SQLAllocHandle (SQL_HANDLE_STMT, handle_, &h); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, *this); + + direct_stmt_.reset (h); + + // Disable escape sequences. + // + r = SQLSetStmtAttr (direct_stmt_, + SQL_ATTR_NOSCAN, + (SQLPOINTER) SQL_NOSCAN_OFF, + 0); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, *this, direct_stmt_); + + // Disable data retrieval for SELECT statements. + // + r = SQLSetStmtAttr (direct_stmt_, + SQL_ATTR_RETRIEVE_DATA, + (SQLPOINTER) SQL_RD_OFF, + 0); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, *this, direct_stmt_); + } + + // Execute. + // + r = SQLExecDirectA (direct_stmt_, (SQLCHAR*) s, (SQLINTEGER) n); + + // SQL_NO_DATA indicates that a DML statement hasn't affected + // any rows. + // + if (r == SQL_NO_DATA) + return 0; + + if (!SQL_SUCCEEDED (r)) + translate_error (r, *this, direct_stmt_); + + // Get the number of affected/returned rows. + // + SQLLEN rows; + + // See if this is a select statement. + // + SQLSMALLINT cols; + r = SQLNumResultCols (direct_stmt_, &cols); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, *this, direct_stmt_); + + if (cols != 0) + { + for (rows = 0;; ++rows) + { + r = SQLFetch (direct_stmt_); + + if (r == SQL_NO_DATA) + break; + else if (!SQL_SUCCEEDED (r)) + translate_error (r, *this, direct_stmt_); + } + + r = SQLCloseCursor (direct_stmt_); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, *this, direct_stmt_); + } + else + { + r = SQLRowCount (direct_stmt_, &rows); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, *this, direct_stmt_); + + // -1 means the row count is not available. In particular, the + // Native Client ODBC driver returns this value for DDL statements. + // + if (rows == -1) + rows = 0; + } + + return static_cast (rows); + } + + // connection_factory + // + connection_factory:: + ~connection_factory () + { + } + + void connection_factory:: + database (database_type& db) + { + odb::connection_factory::db_ = &db; + db_ = &db; + } + } +} diff --git a/libodb-mssql/odb/mssql/connection.hxx b/libodb-mssql/odb/mssql/connection.hxx new file mode 100644 index 0000000..204d37e --- /dev/null +++ b/libodb-mssql/odb/mssql/connection.hxx @@ -0,0 +1,187 @@ +// file : odb/mssql/connection.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_CONNECTION_HXX +#define ODB_MSSQL_CONNECTION_HXX + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class statement_cache; + class connection_factory; + + class connection; + typedef details::shared_ptr connection_ptr; + + class LIBODB_MSSQL_EXPORT connection: public odb::connection + { + public: + typedef mssql::statement_cache statement_cache_type; + typedef mssql::database database_type; + + virtual + ~connection (); + + connection (connection_factory&); + connection (connection_factory&, SQLHDBC handle); + + database_type& + database (); + + public: + virtual transaction_impl* + begin (); + + public: + using odb::connection::execute; + + virtual unsigned long long + execute (const char* statement, std::size_t length); + + // Query preparation. + // + public: + template + prepared_query + prepare_query (const char* name, const char*); + + template + prepared_query + prepare_query (const char* name, const std::string&); + + template + prepared_query + prepare_query (const char* name, const mssql::query_base&); + + template + prepared_query + prepare_query (const char* name, const odb::query_base&); + + // SQL statement tracing. + // + public: + typedef mssql::tracer tracer_type; + + void + tracer (tracer_type& t) + { + odb::connection::tracer (t); + } + + void + tracer (tracer_type* t) + { + odb::connection::tracer (t); + } + + using odb::connection::tracer; + + public: + bool + failed () const + { + return state_ == state_failed; + } + + void + mark_failed () + { + state_ = state_failed; + } + + public: + SQLHDBC + handle () + { + return handle_; + } + + statement_cache_type& + statement_cache () + { + return *statement_cache_; + } + + details::buffer& + long_data_buffer () + { + return long_data_buffer_; + } + + private: + connection (const connection&); + connection& operator= (const connection&); + + private: + friend class transaction_impl; // invalidate_results() + + private: + auto_handle handle_; + + enum + { + state_disconnected, + state_connected, + state_failed + } state_; + + // Statement handle for direct execution. + // + auto_handle direct_stmt_; + details::unique_ptr statement_cache_; + details::buffer long_data_buffer_; + }; + + class LIBODB_MSSQL_EXPORT connection_factory: + public odb::connection_factory + { + public: + typedef mssql::database database_type; + + virtual void + database (database_type&); + + database_type& + database () {return *db_;} + + virtual connection_ptr + connect () = 0; + + virtual + ~connection_factory (); + + connection_factory (): db_ (0) {} + + // Needed to break the circular connection_factory-database dependency + // (odb::connection_factory has the odb::database member). + // + protected: + database_type* db_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_CONNECTION_HXX diff --git a/libodb-mssql/odb/mssql/connection.ixx b/libodb-mssql/odb/mssql/connection.ixx new file mode 100644 index 0000000..8ec8294 --- /dev/null +++ b/libodb-mssql/odb/mssql/connection.ixx @@ -0,0 +1,44 @@ +// file : odb/mssql/connection.ixx +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace mssql + { + inline database& connection:: + database () + { + return static_cast (factory_).database (); + } + + template + inline prepared_query connection:: + prepare_query (const char* n, const char* q) + { + return prepare_query (n, query (q)); + } + + template + inline prepared_query connection:: + prepare_query (const char* n, const std::string& q) + { + return prepare_query (n, query (q)); + } + + template + inline prepared_query connection:: + prepare_query (const char* n, const mssql::query_base& q) + { + return query_::call (*this, n, q); + } + + template + inline prepared_query connection:: + prepare_query (const char* n, const odb::query_base& q) + { + // Translate to native query. + // + return prepare_query (n, mssql::query_base (q)); + } + } +} diff --git a/libodb-mssql/odb/mssql/container-statements.hxx b/libodb-mssql/odb/mssql/container-statements.hxx new file mode 100644 index 0000000..16f4bf9 --- /dev/null +++ b/libodb-mssql/odb/mssql/container-statements.hxx @@ -0,0 +1,353 @@ +// file : odb/mssql/container-statements.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_CONTAINER_STATEMENTS_HXX +#define ODB_MSSQL_CONTAINER_STATEMENTS_HXX + +#include + +#include // std::size_t + +#include +#include +#include + +#include +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class connection; + + // Template argument is the generated abstract container traits type. + // That is, it doesn't need to provide column counts and statements. + // + template + class container_statements + { + public: + typedef T traits; + + typedef typename traits::data_image_type data_image_type; + typedef typename traits::functions_type functions_type; + + typedef mssql::insert_statement insert_statement_type; + typedef mssql::select_statement select_statement_type; + typedef mssql::delete_statement delete_statement_type; + + typedef mssql::connection connection_type; + + container_statements (connection_type&, binding& id_binding); + + connection_type& + connection () + { + return conn_; + } + + // Functions. + // + functions_type& + functions () + { + return functions_; + } + + // Schema version. + // + const schema_version_migration& + version_migration () const {return *svm_;} + + void + version_migration (const schema_version_migration& svm) {svm_ = &svm;} + + // Id image binding (external). + // + const binding& + id_binding () + { + return id_binding_; + } + + // Data image. The image is split into the id (that comes as a + // binding) and index/key plus value which are in data_image_type. + // The select binding is a subset of the full binding (no id). + // + data_image_type& + data_image () + { + return data_image_; + } + + bind* + data_bind () + { + return insert_image_binding_.bind; + } + + bool + data_binding_test_version () const + { + return data_id_binding_version_ != id_binding_.version || + data_image_version_ != data_image_.version || + insert_image_binding_.version == 0; + } + + void + data_binding_update_version () + { + data_id_binding_version_ = id_binding_.version; + data_image_version_ = data_image_.version; + insert_image_binding_.version++; + select_image_binding_.version++; + } + + // + // Statements. + // + + insert_statement_type& + insert_statement () + { + if (insert_ == 0) + insert_.reset ( + new (details::shared) insert_statement_type ( + conn_, + insert_text_, + versioned_, // Process if versioned. + insert_image_binding_, + false, + false, + 0, + false)); + + return *insert_; + } + + select_statement_type& + select_statement () + { + if (select_ == 0) + select_.reset ( + new (details::shared) select_statement_type ( + conn_, + select_text_, + versioned_, // Process if versioned. + false, // Don't optimize. + id_binding_, + select_image_binding_, + false)); + + return *select_; + } + + delete_statement_type& + delete_statement () + { + if (delete_ == 0) + delete_.reset ( + new (details::shared) delete_statement_type ( + conn_, delete_text_, id_binding_, false)); + + return *delete_; + } + + private: + container_statements (const container_statements&); + container_statements& operator= (const container_statements&); + + protected: + connection_type& conn_; + binding& id_binding_; + + functions_type functions_; + + data_image_type data_image_; + std::size_t data_image_version_; + std::size_t data_id_binding_version_; + + binding insert_image_binding_; + binding select_image_binding_; + + const char* insert_text_; + const char* select_text_; + const char* delete_text_; + + bool versioned_; + const schema_version_migration* svm_; + + details::shared_ptr insert_; + details::shared_ptr select_; + details::shared_ptr delete_; + }; + + template + class smart_container_statements: public container_statements + { + public: + typedef T traits; + typedef typename traits::cond_image_type cond_image_type; + + typedef mssql::update_statement update_statement_type; + typedef mssql::delete_statement delete_statement_type; + + typedef mssql::connection connection_type; + + smart_container_statements (connection_type&, binding& id_binding); + + // Condition image. The image is split into the id (that comes as + // a binding) and index/key/value which is in cond_image_type. + // + cond_image_type& + cond_image () + { + return cond_image_; + } + + bind* + cond_bind () + { + return cond_image_binding_.bind; + } + + bool + cond_binding_test_version () const + { + return cond_id_binding_version_ != this->id_binding_.version || + cond_image_version_ != cond_image_.version || + cond_image_binding_.version == 0; + } + + void + cond_binding_update_version () + { + cond_id_binding_version_ = this->id_binding_.version; + cond_image_version_ = cond_image_.version; + cond_image_binding_.version++; + } + + // Update image. The image is split as follows: value comes + // from the data image, id comes as binding, and index/key + // comes from the condition image. + // + bind* + update_bind () + { + return update_image_binding_.bind; + } + + bool + update_binding_test_version () const + { + return update_id_binding_version_ != this->id_binding_.version || + update_cond_image_version_ != cond_image_.version || + update_data_image_version_ != this->data_image_.version || + update_image_binding_.version == 0; + } + + void + update_binding_update_version () + { + update_id_binding_version_ = this->id_binding_.version; + update_cond_image_version_ = cond_image_.version; + update_data_image_version_ = this->data_image_.version; + update_image_binding_.version++; + } + + // + // Statements. + // + + delete_statement_type& + delete_statement () + { + if (this->delete_ == 0) + this->delete_.reset ( + new (details::shared) delete_statement_type ( + this->conn_, + this->delete_text_, + this->cond_image_binding_, + false)); + + return *this->delete_; + } + + update_statement_type& + update_statement () + { + if (update_ == 0) + update_.reset ( + new (details::shared) update_statement_type ( + this->conn_, + update_text_, + this->versioned_, // Process if versioned. + update_image_binding_, + 0, + false)); + + return *update_; + } + + protected: + cond_image_type cond_image_; + std::size_t cond_image_version_; + std::size_t cond_id_binding_version_; + binding cond_image_binding_; + + std::size_t update_id_binding_version_; + std::size_t update_cond_image_version_; + std::size_t update_data_image_version_; + binding update_image_binding_; + + const char* update_text_; + + details::shared_ptr update_; + }; + + // Template argument is the generated concrete container traits type. + // + template + class container_statements_impl: public T::statements_type + { + public: + typedef T traits; + typedef typename T::statements_type base; + typedef mssql::connection connection_type; + + container_statements_impl (connection_type&, binding&); + + private: + container_statements_impl (const container_statements_impl&); + container_statements_impl& operator= (const container_statements_impl&); + + private: + bind data_image_bind_[traits::data_column_count]; + }; + + template + class smart_container_statements_impl: public container_statements_impl + { + public: + typedef T traits; + typedef mssql::connection connection_type; + + smart_container_statements_impl (connection_type&, binding&); + + private: + bind cond_image_bind_[traits::cond_column_count]; + bind update_image_bind_[traits::value_column_count + + traits::cond_column_count]; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_CONTAINER_STATEMENTS_HXX diff --git a/libodb-mssql/odb/mssql/container-statements.txx b/libodb-mssql/odb/mssql/container-statements.txx new file mode 100644 index 0000000..6a45086 --- /dev/null +++ b/libodb-mssql/odb/mssql/container-statements.txx @@ -0,0 +1,96 @@ +// file : odb/mssql/container-statements.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::size_t +#include // std::memset + +namespace odb +{ + namespace mssql + { + // container_statements + // + template + container_statements:: + container_statements (connection_type& conn, binding& id) + : conn_ (conn), + id_binding_ (id), + functions_ (this), + insert_image_binding_ (0, 0), // Initialized by impl. + select_image_binding_ (0, 0), // Initialized by impl. + svm_ (0) + { + functions_.insert_ = &traits::insert; + functions_.select_ = &traits::select; + functions_.delete__ = &traits::delete_; + + data_image_.version = 0; + data_image_version_ = 0; + data_id_binding_version_ = 0; + } + + // smart_container_statements + // + template + smart_container_statements:: + smart_container_statements (connection_type& conn, binding& id) + : container_statements (conn, id), + cond_image_binding_ (0, 0), // Initialized by impl. + update_image_binding_ (0, 0) // Initialized by impl. + { + this->functions_.update_ = &traits::update; + + cond_image_.version = 0; + cond_image_version_ = 0; + cond_id_binding_version_ = 0; + + update_id_binding_version_ = 0; + update_cond_image_version_ = 0; + update_data_image_version_ = 0; + } + + // container_statements_impl + // + template + container_statements_impl:: + container_statements_impl (connection_type& conn, binding& id) + : base (conn, id) + { + this->insert_image_binding_.bind = data_image_bind_; + this->insert_image_binding_.count = traits::data_column_count; + + this->select_image_binding_.bind = data_image_bind_ + + traits::id_column_count; + this->select_image_binding_.count = traits::data_column_count - + traits::id_column_count; + + std::memset (data_image_bind_, 0, sizeof (data_image_bind_)); + + this->insert_text_ = traits::insert_statement; + this->select_text_ = traits::select_statement; + this->delete_text_ = traits::delete_statement; + + this->versioned_ = traits::versioned; + } + + // smart_container_statements_impl + // + template + smart_container_statements_impl:: + smart_container_statements_impl (connection_type& conn, binding& id) + : container_statements_impl (conn, id) + { + this->cond_image_binding_.bind = cond_image_bind_; + this->cond_image_binding_.count = traits::cond_column_count; + + this->update_image_binding_.bind = update_image_bind_; + this->update_image_binding_.count = traits::value_column_count + + traits::cond_column_count; + + std::memset (cond_image_bind_, 0, sizeof (cond_image_bind_)); + std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); + + this->update_text_ = traits::update_statement; + } + } +} diff --git a/libodb-mssql/odb/mssql/database.cxx b/libodb-mssql/odb/mssql/database.cxx new file mode 100644 index 0000000..6e68bcb --- /dev/null +++ b/libodb-mssql/odb/mssql/database.cxx @@ -0,0 +1,580 @@ +// file : odb/mssql/database.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::strcmp, std::strncmp +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +namespace odb +{ + namespace mssql + { + using odb::details::transfer_ptr; + + database:: + database (const string& user, + const string& password, + const string& db, + const string& server, + const string& driver, + const string& extra_connect_string, + transaction_isolation_type transaction_isolation, + SQLHENV environment, + transfer_ptr factory) + : odb::database (id_mssql), + user_ (user), + password_ (password), + db_ (db), + protocol_ (protocol_auto), + port_ (0), + server_ (server), + driver_ (driver), + extra_connect_string_ (extra_connect_string), + transaction_isolation_ (transaction_isolation), + environment_ (environment), + factory_ (factory.transfer ()) + { + init (); + } + + database:: + database (const string& user, + const string& password, + const string& db, + protocol_type protocol, + const string& host, + const string& instance, + const string& driver, + const string& extra_connect_string, + transaction_isolation_type transaction_isolation, + SQLHENV environment, + transfer_ptr factory) + : odb::database (id_mssql), + user_ (user), + password_ (password), + db_ (db), + protocol_ (protocol), + host_ (host), + instance_ (instance), + port_ (0), + driver_ (driver), + extra_connect_string_ (extra_connect_string), + transaction_isolation_ (transaction_isolation), + environment_ (environment), + factory_ (factory.transfer ()) + { + init (); + } + + database:: + database (const string& user, + const string& password, + const string& db, + const string& host, + unsigned int port, + const string& driver, + const string& extra_connect_string, + transaction_isolation_type transaction_isolation, + SQLHENV environment, + transfer_ptr factory) + : odb::database (id_mssql), + user_ (user), + password_ (password), + db_ (db), + protocol_ (protocol_tcp), + host_ (host), + port_ (port), + driver_ (driver), + extra_connect_string_ (extra_connect_string), + transaction_isolation_ (transaction_isolation), + environment_ (environment), + factory_ (factory.transfer ()) + { + init (); + } + + database:: + database (const string& connect_string, + transaction_isolation_type transaction_isolation, + SQLHENV environment, + transfer_ptr factory) + : odb::database (id_mssql), + protocol_ (protocol_auto), + port_ (0), + transaction_isolation_ (transaction_isolation), + connect_string_ (connect_string), + environment_ (environment), + factory_ (factory.transfer ()) + { + init (); + } + + database:: + database (int& argc, + char* argv[], + bool erase, + const string& extra_connect_string, + transaction_isolation_type transaction_isolation, + SQLHENV environment, + transfer_ptr factory) + : odb::database (id_mssql), + protocol_ (protocol_auto), + port_ (0), + extra_connect_string_ (extra_connect_string), + transaction_isolation_ (transaction_isolation), + environment_ (environment), + factory_ (factory.transfer ()) + { + using namespace details; + + try + { + cli::argv_file_scanner scan (argc, argv, "--options-file", erase); + options ops (scan, cli::unknown_mode::skip, cli::unknown_mode::skip); + + user_ = ops.user (); + password_ = ops.password (); + db_ = ops.database (); + server_ = ops.server (); + driver_ = ops.driver (); + } + catch (const cli::exception& e) + { + ostringstream oss; + oss << e; + throw cli_exception (oss.str ()); + } + + init (); + } + + /* + + NOTE: This code hasn't been tested. + + void database:: + parse () + { + // Parse the server string and extract individual parts (protocol, + // host, instance, and port). + // + string port; + + if (server_.compare (0, 4, "lpc:") == 0) + { + // lpc:[\] + // + protocol_ = protocol_shm; + string::size_type p (server_.find (4, '\\')); + + if (p == string::npos) + host_.assign (server_, 4, string::npos); + else + { + host_.assign (server_, 4, p - 4); + instance_.assign (server_, p + 1, string::npos); + } + } + else if (server_.compare (0, 3, "np:") == 0) + { + // np:\pipe\[MSSQL$\]sql\query + // + protocol_ = protocol_pipe; + + string::size_type p (server_.find (3, '\\')); + + if (p != string::npos) + { + host_.assign (server_, 3, p - 3); + + p = server_.find (p + 1, '$'); + + if (p != string::npos) + { + p++; + instance_.assign (server_, p, server_.find (p, '\\') - p); + } + } + } + else + { + // [\][,] + // tcp:[\][,] + // + string::size_type p1 (0), p2; + + if (server_.compare (0, 4, "tcp:") == 0) + { + protocol_ = protocol_tcp; + p1 = 4; + } + + p2 = server_.find (p1, '\\'); + + if (p2 == string::npos) + { + p2 = server_.find (p1, ','); + + if (p2 == string::npos) + host_.assign (server_, p1, string::npos); + else + { + host_.assign (server_, 4, p2 - p1); + port.assign (server_, p2 + 1, string::npos); + } + } + else + { + host_.assign (server_, 4, p2 - p1); + + p1 = server_.find (p2 + 1, ','); + + if (p1 == string::npos) + instance_.assign (server_, p2 + 1, string::npos); + else + { + instance_.assign (server_, p2 + 1, p1 - p2 - 1); + port.assign (server_, p1 + 1, string::npos); + } + } + } + + if (!port.empty ()) + { + istringstream is (port); + is >> port; + protocol_ = protocol_tcp; + } + } + */ + + void database:: + init () + { + SQLRETURN r; + + if (environment_ == 0) + { + r = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &environment_); + + if (!SQL_SUCCEEDED (r)) + throw database_exception ( + 0, "?????", "unable to allocate environment handle"); + + auto_environment_.reset (environment_); + + // Set ODBC version. + // + r = SQLSetEnvAttr (environment_, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER) SQL_OV_ODBC3, + 0); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, environment_, SQL_HANDLE_ENV); + } + + // Build the connection string. + // + if (connect_string_.empty ()) + { + // Find the driver. + // + if (driver_.empty ()) + { + for (bool first (true);; ) + { + char desc[256]; + SQLSMALLINT desc_size, attr_size; + + r = SQLDriversA (environment_, + first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT, + (SQLCHAR*) desc, + sizeof (desc), + &desc_size, + 0, + 0, + &attr_size); + + if (r == SQL_NO_DATA) + break; + else if (!SQL_SUCCEEDED (r)) + translate_error (r, environment_, SQL_HANDLE_ENV); + + // Native Client 9.0 (first version). + // + if (strcmp (desc, "SQL Native Client") == 0 || + strncmp (desc, "SQL Server Native Client", 24) == 0) + { + // Compare driver strings lexicographically. Provided that + // Microsoft keeps its naming consistent, we will get the + // correct result. For example, "SQL Server Native Client + // 10.0" (SQL Server 2008) will be greater than "SQL Native + // Client" (SQL Server 2005). Similarly, "SQL Server Native + // Client 11.0" (SQL Server 2012) will be preferred over + // "SQL Server Native Client 10.0" (SQL Server 2008). + // + if (desc > driver_) + driver_ = desc; + } + + if (first) + first = false; + } + } + + connect_string_ += "DRIVER={"; + connect_string_ += driver_; + connect_string_ += "};"; + + // If necessary, assemble the server address string, depending + // on which protocol we are using. + if (server_.empty ()) + { + switch (protocol_) + { + case protocol_auto: + { + server_ = (host_.empty () ? "localhost" : host_.c_str ()); + + if (!instance_.empty ()) + { + server_ += '\\'; + server_ += instance_; + } + + break; + } + case protocol_tcp: + { + server_ = "tcp:"; + server_ += (host_.empty () ? "localhost" : host_.c_str ()); + + // Port seems to take precedence over instance. For example, + // if you specify both, and the instance name is invalid, the + // Native Client driver still connects without any problems. + // + if (port_ != 0) + { + ostringstream os; + os << port_; + server_ += ','; + server_ += os.str (); + } + else if (!instance_.empty ()) + { + server_ += '\\'; + server_ += instance_; + } + + break; + } + case protocol_lpc: + { + server_ = "lpc:"; + server_ += (host_.empty () ? "localhost" : host_.c_str ()); + + if (!instance_.empty ()) + { + server_ += '\\'; + server_ += instance_; + } + + break; + } + case protocol_np: + { + server_ = "np:\\\\"; + server_ += (host_.empty () ? "." : host_.c_str ()); + server_ += "\\pipe\\"; + + if (!instance_.empty ()) + { + server_ += "MSSQL$"; + server_ += instance_; + server_ += '\\'; + } + + server_ += "sql\\query"; + break; + } + } + } + + // The Address attribute seems to be preferred over SERVER. However, + // SQL Server 2005 Native Client only seem to support Address since + // SP1. Since we don't know the exact driver version, for now always + // use SERVER with SQL Server 2005 driver. + // + connect_string_ += (driver_ == "SQL Native Client" + ? "SERVER={" + : "Address={"); + + connect_string_ += server_; + connect_string_ += "};"; + + // Add login information. + // + if (user_.empty ()) + // Windows authentication. + // + connect_string_ += "Trusted_Connection=yes;"; + else + { + connect_string_ += "UID={"; + connect_string_ += user_; + connect_string_ += "};"; + + if (!password_.empty ()) + { + connect_string_ += "PWD={"; + connect_string_ += password_; + connect_string_ += "};"; + } + } + + // Add database. + // + if (!db_.empty ()) + { + connect_string_ += "Database={"; + connect_string_ += db_; + connect_string_ += "};"; + } + + // Add any extra connection attributes. + // + if (!extra_connect_string_.empty ()) + connect_string_ += extra_connect_string_; + } + + if (!factory_) + factory_.reset (new connection_pool_factory ()); + + factory_->database (*this); + } + + void database:: + print_usage (ostream& os) + { + details::options::print_usage (os); + } + + database:: + ~database () + { + } + + transaction_impl* database:: + begin () + { + return new transaction_impl (*this); + } + + odb::connection* database:: + connection_ () + { + connection_ptr c (factory_->connect ()); + return c.release (); + } + + const database::schema_version_info& database:: + load_schema_version (const string& name) const + { + schema_version_info& svi (schema_version_map_[name]); + + // Construct the SELECT statement text. + // + string text ("SELECT [version], [migration] FROM "); + + if (!svi.version_table.empty ()) + text += svi.version_table; // Already quoted. + else if (!schema_version_table_.empty ()) + text += schema_version_table_; // Already quoted. + else + text += "[schema_version]"; + + text += " WHERE [name] = ?"; + + // Bind parameters and results. + // + SQLLEN psize[1] = {static_cast (name.size ())}; + bind pbind[1] = { + {bind::string, const_cast (name.c_str ()), &psize[0], 0}}; + binding param (pbind, 1); + param.version++; + + signed char migration; + SQLLEN rsize[2]; + bind rbind[2] = {{bind::bigint, &svi.version, &rsize[0], 0}, + {bind::bit, &migration, &rsize[1], 0}}; + binding result (rbind, 2); + result.version++; + + // If we are not in transaction, start one. + // + transaction t; + if (!transaction::has_current ()) + t.reset (factory_->connect ()->begin (), false); + + mssql::connection& c ( + t.finalized () + ? transaction::current ().connection (const_cast (*this)) + : t.connection (const_cast (*this))); + + try + { + select_statement st (c, + text.c_str (), + false, // Don't process. + false, // Don't optimize. + param, + result, + false); + + st.execute (); + auto_result ar (st); + + switch (st.fetch ()) + { + case select_statement::success: + { + svi.migration = migration != 0; + assert (st.fetch () == select_statement::no_data); + break; + } + case select_statement::no_data: + { + svi.version = 0; // No schema. + break; + } + } + } + catch (const database_exception& e) + { + // Detect the case where there is no version table. The SQL Server- + // specific error code (208) seems to be too generic. + // + if (e.begin ()->sqlstate () == "42S02") + svi.version = 0; // No schema. + else + throw; + } + + if (!t.finalized ()) + t.commit (); + + return svi; + } + } +} diff --git a/libodb-mssql/odb/mssql/database.hxx b/libodb-mssql/odb/mssql/database.hxx new file mode 100644 index 0000000..5367bc5 --- /dev/null +++ b/libodb-mssql/odb/mssql/database.hxx @@ -0,0 +1,629 @@ +// file : odb/mssql/database.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_DATABASE_HXX +#define ODB_MSSQL_DATABASE_HXX + +#include + +#include +#include // std::ostream + +#include +#include // ODB_CXX11 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class transaction_impl; + + enum protocol + { + protocol_auto, + protocol_tcp, // TCP/IP. + protocol_lpc, // Shared memory (local procedure call). + protocol_np // Named pipes. + }; + + enum transaction_isolation + { + isolation_read_uncommitted, + isolation_read_committed, // SQL Server default. + isolation_repeatable_read, + isolation_snapshot, + isolation_serializable + }; + + class LIBODB_MSSQL_EXPORT database: public odb::database + { + public: + typedef mssql::protocol protocol_type; + typedef mssql::transaction_isolation transaction_isolation_type; + + // Connect to the specified server using the latest available SQL + // Server Native Client ODBC driver by default. If user is empty, + // then use Windows authentication. If db is empty, then use the + // default database for this user. + // + database (const std::string& user, + const std::string& password, + const std::string& db, + const std::string& server, + const std::string& driver = "", + const std::string& extra_connect_string = "", + transaction_isolation_type = isolation_read_committed, + SQLHENV environment = 0, + details::transfer_ptr = + details::transfer_ptr ()); + + // By default connect to the default instance on localhost using + // default protocol and the latest available SQL Server Native + // Client ODBC driver. If user is empty, then use Windows + // authentication. If db is empty, then use the default database + // for this user. + // + database (const std::string& user, + const std::string& password, + const std::string& db, + protocol_type protocol = protocol_auto, + const std::string& host = "", + const std::string& instance = "", + const std::string& driver = "", + const std::string& extra_connect_string = "", + transaction_isolation_type = isolation_read_committed, + SQLHENV environment = 0, + details::transfer_ptr = + details::transfer_ptr ()); + + // Connect using TCP/IP to the specified host and port. If port is + // 0, use the default port (1433). + // + database (const std::string& user, + const std::string& password, + const std::string& db, + const std::string& host, + unsigned int port, + const std::string& driver = "", + const std::string& extra_connect_string = "", + transaction_isolation_type = isolation_read_committed, + SQLHENV environment = 0, + details::transfer_ptr = + details::transfer_ptr ()); + + // Connect using a custom SQL Server Native Client ODBC driver + // conection string. + // + database (const std::string& connect_string, + transaction_isolation_type = isolation_read_committed, + SQLHENV environment = 0, + details::transfer_ptr = + details::transfer_ptr ()); + + // Extract the database parameters from the command line. The + // following options are recognized: + // + // --user | -U + // --password | -P + // --database | -d + // --server | -S + // --driver + // --options-file + // + // For more information, see the output of the print_usage() function + // below. If erase is true, the above options are removed from the + // argv array and the argc count is updated accordingly. This + // constructor may throw the cli_exception exception. + // + database (int& argc, + char* argv[], + bool erase = false, + const std::string& extra_connect_string = "", + transaction_isolation_type = isolation_read_committed, + SQLHENV environment = 0, + details::transfer_ptr = + details::transfer_ptr ()); + + // Move-constructible but not move-assignable. + // + // Note: noexcept is not specified since odb::database(odb::database&&) + // can throw. + // +#ifdef ODB_CXX11 + database (database&&); +#endif + + static void + print_usage (std::ostream&); + + // Object persistence API. + // + public: + + // Make the object persistent. + // + template + typename object_traits::id_type + persist (T& object); + + template + typename object_traits::id_type + persist (const T& object); + + template + typename object_traits::id_type + persist (T* obj_ptr); + + template class P> + typename object_traits::id_type + persist (const P& obj_ptr); + + template class P> + typename object_traits::id_type + persist (const P& obj_ptr); + + template class P> + typename object_traits::id_type + persist (P& obj_ptr); + + template class P> + typename object_traits::id_type + persist (P& obj_ptr); + + template + typename object_traits::id_type + persist (const typename object_traits::pointer_type& obj_ptr); + + // Bulk persist. Can be a range of references or pointers (including + // smart pointers) to objects. + // + template + void + persist (I begin, I end, bool continue_failed = true); + + // Load an object. Throw object_not_persistent if not found. + // + template + typename object_traits::pointer_type + load (const typename object_traits::id_type& id); + + template + void + load (const typename object_traits::id_type& id, T& object); + + // Load (or reload, if it is already loaded) a section of an object. + // + template + void + load (T& object, section&); + + // Reload an object. + // + template + void + reload (T& object); + + template + void + reload (T* obj_ptr); + + template class P> + void + reload (const P& obj_ptr); + + template class P> + void + reload (const P& obj_ptr); + + template class P> + void + reload (P& obj_ptr); + + template class P> + void + reload (P& obj_ptr); + + template + void + reload (const typename object_traits::pointer_type& obj_ptr); + + // Loan an object if found. Return NULL/false if not found. + // + template + typename object_traits::pointer_type + find (const typename object_traits::id_type& id); + + template + bool + find (const typename object_traits::id_type& id, T& object); + + // Update the state of a modified objects. + // + template + void + update (T& object); + + template + void + update (T* obj_ptr); + + template class P> + void + update (const P& obj_ptr); + + template class P> + void + update (const P& obj_ptr); + + template class P> + void + update (P& obj_ptr); + + template class P> + void + update (P& obj_ptr); + + template + void + update (const typename object_traits::pointer_type& obj_ptr); + + // Bulk update. Can be a range of references or pointers (including + // smart pointers) to objects. + // + template + void + update (I begin, I end, bool continue_failed = true); + + // Update a section of an object. Throws the section_not_loaded + // exception if the section is not loaded. Note also that this + // function does not clear the changed flag if it is set. + // + template + void + update (const T& object, const section&); + + // Make the object transient. Throw object_not_persistent if not + // found. + // + template + void + erase (const typename object_traits::id_type& id); + + template + void + erase (T& object); + + template + void + erase (T* obj_ptr); + + template class P> + void + erase (const P& obj_ptr); + + template class P> + void + erase (const P& obj_ptr); + + template class P> + void + erase (P& obj_ptr); + + template class P> + void + erase (P& obj_ptr); + + template + void + erase (const typename object_traits::pointer_type& obj_ptr); + + // Bulk erase. + // + template + void + erase (I id_begin, I id_end, bool continue_failed = true); + + // Can be a range of references or pointers (including smart pointers) + // to objects. + // + template + void + erase (I obj_begin, I obj_end, bool continue_failed = true); + + // Erase multiple objects matching a query predicate. + // + template + unsigned long long + erase_query (); + + template + unsigned long long + erase_query (const char*); + + template + unsigned long long + erase_query (const std::string&); + + template + unsigned long long + erase_query (const mssql::query_base&); + + template + unsigned long long + erase_query (const odb::query_base&); + + // Query API. + // + template + result + query (); + + template + result + query (const char*); + + template + result + query (const std::string&); + + template + result + query (const mssql::query_base&); + + template + result + query (const odb::query_base&); + + // Query one API. + // + template + typename result::pointer_type + query_one (); + + template + bool + query_one (T& object); + + template + T + query_value (); + + template + typename result::pointer_type + query_one (const char*); + + template + bool + query_one (const char*, T& object); + + template + T + query_value (const char*); + + template + typename result::pointer_type + query_one (const std::string&); + + template + bool + query_one (const std::string&, T& object); + + template + T + query_value (const std::string&); + + template + typename result::pointer_type + query_one (const mssql::query_base&); + + template + bool + query_one (const mssql::query_base&, T& object); + + template + T + query_value (const mssql::query_base&); + + template + typename result::pointer_type + query_one (const odb::query_base&); + + template + bool + query_one (const odb::query_base&, T& object); + + template + T + query_value (const odb::query_base&); + + // Query preparation. + // + template + prepared_query + prepare_query (const char* name, const char*); + + template + prepared_query + prepare_query (const char* name, const std::string&); + + template + prepared_query + prepare_query (const char* name, const mssql::query_base&); + + template + prepared_query + prepare_query (const char* name, const odb::query_base&); + + // Transactions. + // + public: + virtual transaction_impl* + begin (); + + public: + connection_ptr + connection (); + + public: + const std::string& + user () const + { + return user_; + } + + const std::string& + password () const + { + return password_; + } + + const std::string& + db () const + { + return db_; + } + + protocol_type + protocol () const + { + return protocol_; + } + + const std::string& + host () const + { + return host_; + } + + const std::string& + instance () const + { + return instance_; + } + + unsigned int + port () const + { + return port_; + } + + const std::string& + server () const + { + return server_; + } + + const std::string& + driver () const + { + return driver_; + } + + const std::string& + extra_connect_string () const + { + return extra_connect_string_; + } + + transaction_isolation_type + transaction_isolation () const + { + return transaction_isolation_; + } + + const std::string& + connect_string () const + { + return connect_string_; + } + + SQLHENV + environment () + { + return environment_; + } + + // SQL statement tracing. + // + public: + typedef mssql::tracer tracer_type; + + void + tracer (tracer_type& t) + { + odb::database::tracer (t); + } + + void + tracer (tracer_type* t) + { + odb::database::tracer (t); + } + + using odb::database::tracer; + + // Database schema version. + // + protected: + virtual const schema_version_info& + load_schema_version (const std::string& schema_name) const; + + public: + // Database id constant (useful for meta-programming). + // + static const odb::database_id database_id = id_mssql; + + public: + virtual + ~database (); + + protected: + virtual odb::connection* + connection_ (); + + private: + void + init (); + + private: + // Note: remember to update move ctor if adding any new members. + // + std::string user_; + std::string password_; + std::string db_; + protocol_type protocol_; + std::string host_; + std::string instance_; + unsigned int port_; + std::string server_; + std::string driver_; + std::string extra_connect_string_; + transaction_isolation_type transaction_isolation_; + std::string connect_string_; + + auto_handle auto_environment_; + SQLHENV environment_; + + details::unique_ptr factory_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_DATABASE_HXX diff --git a/libodb-mssql/odb/mssql/database.ixx b/libodb-mssql/odb/mssql/database.ixx new file mode 100644 index 0000000..ae1b83b --- /dev/null +++ b/libodb-mssql/odb/mssql/database.ixx @@ -0,0 +1,644 @@ +// file : odb/mssql/database.ixx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // move() + +#include + +namespace odb +{ + namespace mssql + { +#ifdef ODB_CXX11 + inline database:: + database (database&& db) // Has to be inline. + : odb::database (std::move (db)), + user_ (std::move (db.user_)), + password_ (std::move (db.password_)), + db_ (std::move (db.db_)), + protocol_ (db.protocol_), + host_ (std::move (db.host_)), + instance_ (std::move (db.instance_)), + port_ (db.port_), + server_ (std::move (db.server_)), + driver_ (std::move (db.driver_)), + extra_connect_string_ (std::move (db.extra_connect_string_)), + transaction_isolation_ (db.transaction_isolation_), + connect_string_ (std::move (db.connect_string_)), + auto_environment_ (std::move (db.auto_environment_)), + environment_ (db.environment_), + factory_ (std::move (db.factory_)) + { + factory_->database (*this); // New database instance. + } +#endif + + inline connection_ptr database:: + connection () + { + // Go through the virtual connection_() function instead of + // directly to allow overriding. + // + return connection_ptr ( + static_cast (connection_ ())); + } + + template + inline typename object_traits::id_type database:: + persist (T& obj) + { + return persist_ (obj); + } + + template + inline typename object_traits::id_type database:: + persist (const T& obj) + { + return persist_ (obj); + } + + template + inline typename object_traits::id_type database:: + persist (T* p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + return persist_ (pobj); + } + + template class P> + inline typename object_traits::id_type database:: + persist (const P& p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + return persist_ (pobj); + } + + template class P> + inline typename object_traits::id_type database:: + persist (const P& p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + return persist_ (pobj); + } + + template class P> + inline typename object_traits::id_type database:: + persist (P& p) + { + const P& cr (p); + return persist (cr); + } + + template class P> + inline typename object_traits::id_type database:: + persist (P& p) + { + const P& cr (p); + return persist (cr); + } + + template + inline typename object_traits::id_type database:: + persist (const typename object_traits::pointer_type& pobj) + { + return persist_ (pobj); + } + + template + inline void database:: + persist (I b, I e, bool cont) + { + persist_ (b, e, cont); + } + + template + inline typename object_traits::pointer_type database:: + load (const typename object_traits::id_type& id) + { + return load_ (id); + } + + template + inline void database:: + load (const typename object_traits::id_type& id, T& obj) + { + return load_ (id, obj); + } + + template + inline void database:: + load (T& obj, section& s) + { + return load_ (obj, s); + } + + template + inline typename object_traits::pointer_type database:: + find (const typename object_traits::id_type& id) + { + return find_ (id); + } + + template + inline bool database:: + find (const typename object_traits::id_type& id, T& obj) + { + return find_ (id, obj); + } + + template + inline void database:: + reload (T& obj) + { + reload_ (obj); + } + + template + inline void database:: + reload (T* p) + { + reload (*p); + } + + template class P> + inline void database:: + reload (const P& p) + { + reload (odb::pointer_traits< P >::get_ref (p)); + } + + template class P> + inline void database:: + reload (const P& p) + { + reload (odb::pointer_traits< P >::get_ref (p)); + } + + template class P> + inline void database:: + reload (P& p) + { + reload (odb::pointer_traits< P >::get_ref (p)); + } + + template class P> + inline void database:: + reload (P& p) + { + reload (odb::pointer_traits< P >::get_ref (p)); + } + + template + inline void database:: + reload (const typename object_traits::pointer_type& pobj) + { + typedef typename object_traits::pointer_type pointer_type; + + reload (odb::pointer_traits::get_ref (pobj)); + } + + template + inline void database:: + update (T& obj) + { + update_ (obj); + } + + template + inline void database:: + update (T* p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + update_ (pobj); + } + + template class P> + inline void database:: + update (const P& p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + update_ (pobj); + } + + template class P> + inline void database:: + update (const P& p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + update_ (pobj); + } + + template class P> + inline void database:: + update (P& p) + { + const P& cr (p); + update (cr); + } + + template class P> + inline void database:: + update (P& p) + { + const P& cr (p); + update (cr); + } + + template + inline void database:: + update (const typename object_traits::pointer_type& pobj) + { + update_ (pobj); + } + + template + inline void database:: + update (I b, I e, bool cont) + { + update_ (b, e, cont); + } + + template + inline void database:: + update (const T& obj, const section& s) + { + update_ (obj, s); + } + + template + inline void database:: + erase (const typename object_traits::id_type& id) + { + return erase_ (id); + } + + template + inline void database:: + erase (T& obj) + { + return erase_ (obj); + } + + template + inline void database:: + erase (T* p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + erase_ (pobj); + } + + template class P> + inline void database:: + erase (const P& p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + erase_ (pobj); + } + + template class P> + inline void database:: + erase (const P& p) + { + typedef typename object_traits::pointer_type object_pointer; + + // The passed pointer should be the same or implicit-convertible + // to the object pointer. This way we make sure the object pointer + // does not assume ownership of the passed object. + // + const object_pointer& pobj (p); + + erase_ (pobj); + } + + template class P> + inline void database:: + erase (P& p) + { + const P& cr (p); + erase (cr); + } + + template class P> + inline void database:: + erase (P& p) + { + const P& cr (p); + erase (cr); + } + + template + inline void database:: + erase (const typename object_traits::pointer_type& pobj) + { + erase_ (pobj); + } + + template + inline void database:: + erase (I idb, I ide, bool cont) + { + erase_id_ (idb, ide, cont); + } + + template + inline void database:: + erase (I ob, I oe, bool cont) + { + erase_object_ (ob, oe, cont); + } + + template + inline unsigned long long database:: + erase_query () + { + // T is always object_type. + // + return erase_query (mssql::query_base ()); + } + + template + inline unsigned long long database:: + erase_query (const char* q) + { + // T is always object_type. + // + return erase_query (mssql::query_base (q)); + } + + template + inline unsigned long long database:: + erase_query (const std::string& q) + { + // T is always object_type. + // + return erase_query (mssql::query_base (q)); + } + + template + inline unsigned long long database:: + erase_query (const mssql::query_base& q) + { + // T is always object_type. + // + return object_traits_impl::erase_query (*this, q); + } + + template + inline unsigned long long database:: + erase_query (const odb::query_base& q) + { + // Translate to native query. + // + return erase_query (mssql::query_base (q)); + } + + template + inline result database:: + query () + { + return query (mssql::query_base ()); + } + + template + inline result database:: + query (const char* q) + { + return query (mssql::query_base (q)); + } + + template + inline result database:: + query (const std::string& q) + { + return query (mssql::query_base (q)); + } + + template + inline result database:: + query (const mssql::query_base& q) + { + // T is always object_type. We also don't need to check for transaction + // here; object_traits::query () does this. + // + return query_::call (*this, q); + } + + template + inline result database:: + query (const odb::query_base& q) + { + // Translate to native query. + // + return query (mssql::query_base (q)); + } + + template + inline typename result::pointer_type database:: + query_one () + { + return query_one (mssql::query_base ()); + } + + template + inline bool database:: + query_one (T& o) + { + return query_one (mssql::query_base (), o); + } + + template + inline T database:: + query_value () + { + return query_value (mssql::query_base ()); + } + + template + inline typename result::pointer_type database:: + query_one (const char* q) + { + return query_one (mssql::query_base (q)); + } + + template + inline bool database:: + query_one (const char* q, T& o) + { + return query_one (mssql::query_base (q), o); + } + + template + inline T database:: + query_value (const char* q) + { + return query_value (mssql::query_base (q)); + } + + template + inline typename result::pointer_type database:: + query_one (const std::string& q) + { + return query_one (mssql::query_base (q)); + } + + template + inline bool database:: + query_one (const std::string& q, T& o) + { + return query_one (mssql::query_base (q), o); + } + + template + inline T database:: + query_value (const std::string& q) + { + return query_value (mssql::query_base (q)); + } + + template + inline typename result::pointer_type database:: + query_one (const mssql::query_base& q) + { + // T is always object_type. We also don't need to check for transaction + // here; object_traits::query () does this. + // + return query_one_ (q); + } + + template + inline bool database:: + query_one (const mssql::query_base& q, T& o) + { + // T is always object_type. We also don't need to check for transaction + // here; object_traits::query () does this. + // + return query_one_ (q, o); + } + + template + inline T database:: + query_value (const mssql::query_base& q) + { + // T is always object_type. We also don't need to check for transaction + // here; object_traits::query () does this. + // + return query_value_ (q); + } + + template + inline typename result::pointer_type database:: + query_one (const odb::query_base& q) + { + // Translate to native query. + // + return query_one (mssql::query_base (q)); + } + + template + inline bool database:: + query_one (const odb::query_base& q, T& o) + { + // Translate to native query. + // + return query_one (mssql::query_base (q), o); + } + + template + inline T database:: + query_value (const odb::query_base& q) + { + // Translate to native query. + // + return query_value (mssql::query_base (q)); + } + + template + inline prepared_query database:: + prepare_query (const char* n, const char* q) + { + return prepare_query (n, mssql::query_base (q)); + } + + template + inline prepared_query database:: + prepare_query (const char* n, const std::string& q) + { + return prepare_query (n, mssql::query_base (q)); + } + + template + inline prepared_query database:: + prepare_query (const char* n, const mssql::query_base& q) + { + // Throws if not in transaction. + // + mssql::connection& c (transaction::current ().connection (*this)); + return c.prepare_query (n, q); + } + + template + inline prepared_query database:: + prepare_query (const char* n, const odb::query_base& q) + { + // Translate to native query. + // + return prepare_query (n, mssql::query_base (q)); + } + } +} diff --git a/libodb-mssql/odb/mssql/details/.gitignore b/libodb-mssql/odb/mssql/details/.gitignore new file mode 100644 index 0000000..b298f89 --- /dev/null +++ b/libodb-mssql/odb/mssql/details/.gitignore @@ -0,0 +1 @@ +/options.?xx diff --git a/libodb-mssql/odb/mssql/details/build2/config-stub.h b/libodb-mssql/odb/mssql/details/build2/config-stub.h new file mode 100644 index 0000000..e402d2f --- /dev/null +++ b/libodb-mssql/odb/mssql/details/build2/config-stub.h @@ -0,0 +1,5 @@ +/* file : odb/mssql/details/build2/config-stub.h + * license : ODB NCUEL; see accompanying LICENSE file + */ + +#include diff --git a/libodb-mssql/odb/mssql/details/build2/config-vc-stub.h b/libodb-mssql/odb/mssql/details/build2/config-vc-stub.h new file mode 100644 index 0000000..36ae27f --- /dev/null +++ b/libodb-mssql/odb/mssql/details/build2/config-vc-stub.h @@ -0,0 +1,5 @@ +/* file : odb/mssql/details/build2/config-vc-stub.h + * license : ODB NCUEL; see accompanying LICENSE file + */ + +#include diff --git a/libodb-mssql/odb/mssql/details/build2/config-vc.h b/libodb-mssql/odb/mssql/details/build2/config-vc.h new file mode 100644 index 0000000..1489d09 --- /dev/null +++ b/libodb-mssql/odb/mssql/details/build2/config-vc.h @@ -0,0 +1,15 @@ +/* file : odb/mssql/details/build2/config-vc.h + * license : ODB NCUEL; see accompanying LICENSE file + */ + +/* Configuration file for Windows/VC++ for the build2 build. */ + +#ifndef ODB_MSSQL_DETAILS_CONFIG_VC_H +#define ODB_MSSQL_DETAILS_CONFIG_VC_H + +/* Define LIBODB_MSSQL_BUILD2 for the installed case. */ +#ifndef LIBODB_MSSQL_BUILD2 +# define LIBODB_MSSQL_BUILD2 +#endif + +#endif /* ODB_MSSQL_DETAILS_CONFIG_VC_H */ diff --git a/libodb-mssql/odb/mssql/details/build2/config.h b/libodb-mssql/odb/mssql/details/build2/config.h new file mode 100644 index 0000000..de736e2 --- /dev/null +++ b/libodb-mssql/odb/mssql/details/build2/config.h @@ -0,0 +1,17 @@ +/* file : odb/mssql/details/build2/config.h + * license : ODB NCUEL; see accompanying LICENSE file + */ + +/* Static configuration file for the build2 build. The installed case + (when LIBODB_MSSQL_BUILD2 is not necessarily defined) is the only + reason we have it. */ + +#ifndef ODB_MSSQL_DETAILS_CONFIG_H +#define ODB_MSSQL_DETAILS_CONFIG_H + +/* Define LIBODB_MSSQL_BUILD2 for the installed case. */ +#ifndef LIBODB_MSSQL_BUILD2 +# define LIBODB_MSSQL_BUILD2 +#endif + +#endif /* ODB_MSSQL_DETAILS_CONFIG_H */ diff --git a/libodb-mssql/odb/mssql/details/config-vc.h b/libodb-mssql/odb/mssql/details/config-vc.h new file mode 100644 index 0000000..e93b86b --- /dev/null +++ b/libodb-mssql/odb/mssql/details/config-vc.h @@ -0,0 +1,5 @@ +/* file : odb/mssql/details/config-vc.h + * license : ODB NCUEL; see accompanying LICENSE file + */ + +/* Dummy configuration file for Windows/VC++. */ diff --git a/libodb-mssql/odb/mssql/details/config.h.in b/libodb-mssql/odb/mssql/details/config.h.in new file mode 100644 index 0000000..9ddb75a --- /dev/null +++ b/libodb-mssql/odb/mssql/details/config.h.in @@ -0,0 +1,12 @@ +/* file : odb/mssql/details/config.h.in + * license : ODB NCUEL; see accompanying LICENSE file + */ + +/* This file is automatically processed by configure. */ + +#ifndef ODB_MSSQL_DETAILS_CONFIG_H +#define ODB_MSSQL_DETAILS_CONFIG_H + +#undef LIBODB_MSSQL_STATIC_LIB + +#endif /* ODB_MSSQL_DETAILS_CONFIG_H */ diff --git a/libodb-mssql/odb/mssql/details/config.hxx b/libodb-mssql/odb/mssql/details/config.hxx new file mode 100644 index 0000000..ff2a5af --- /dev/null +++ b/libodb-mssql/odb/mssql/details/config.hxx @@ -0,0 +1,21 @@ +// file : odb/mssql/details/config.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_DETAILS_CONFIG_HXX +#define ODB_MSSQL_DETAILS_CONFIG_HXX + +// no pre + +#ifdef ODB_COMPILER +# error libodb-mssql header included in odb-compiled header +#elif !defined(LIBODB_MSSQL_BUILD2) +# ifdef _MSC_VER +# include +# else +# include +# endif +#endif + +// no post + +#endif // ODB_MSSQL_DETAILS_CONFIG_HXX diff --git a/libodb-mssql/odb/mssql/details/conversion.hxx b/libodb-mssql/odb/mssql/details/conversion.hxx new file mode 100644 index 0000000..35f368d --- /dev/null +++ b/libodb-mssql/odb/mssql/details/conversion.hxx @@ -0,0 +1,58 @@ +// file : odb/mssql/details/conversion.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_DETAILS_CONVERSION_HXX +#define ODB_MSSQL_DETAILS_CONVERSION_HXX + +#include + +#include + +namespace odb +{ + // @@ Revise this. + // + namespace details {} + + namespace mssql + { + namespace details + { + using namespace odb::details; + + // Detect whether conversion is specified in type_traits. + // + template + meta::yes + conversion_p_test (typename type_traits::conversion*); + + template + meta::no + conversion_p_test (...); + + template + struct conversion_p + { + static const bool value = + sizeof (conversion_p_test (0)) == sizeof (meta::yes); + }; + + template ::value> + struct conversion; + + template + struct conversion + { + static const char* to () {return type_traits::conversion::to ();} + }; + + template + struct conversion + { + static const char* to () {return 0;} + }; + } + } +} + +#endif // ODB_MSSQL_DETAILS_CONVERSION_HXX diff --git a/libodb-mssql/odb/mssql/details/export.hxx b/libodb-mssql/odb/mssql/details/export.hxx new file mode 100644 index 0000000..94e762b --- /dev/null +++ b/libodb-mssql/odb/mssql/details/export.hxx @@ -0,0 +1,78 @@ +// file : odb/mssql/details/export.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_DETAILS_EXPORT_HXX +#define ODB_MSSQL_DETAILS_EXPORT_HXX + +#include + +#include + +// Normally we don't export class templates (but do complete specializations), +// inline functions, and classes with only inline member functions. Exporting +// classes that inherit from non-exported/imported bases (e.g., std::string) +// will end up badly. The only known workarounds are to not inherit or to not +// export. Also, MinGW GCC doesn't like seeing non-exported function being +// used before their inline definition. The workaround is to reorder code. In +// the end it's all trial and error. + +#ifdef LIBODB_MSSQL_BUILD2 + +#if defined(LIBODB_MSSQL_STATIC) // Using static. +# define LIBODB_MSSQL_EXPORT +#elif defined(LIBODB_MSSQL_STATIC_BUILD) // Building static. +# define LIBODB_MSSQL_EXPORT +#elif defined(LIBODB_MSSQL_SHARED) // Using shared. +# ifdef _WIN32 +# define LIBODB_MSSQL_EXPORT __declspec(dllimport) +# else +# define LIBODB_MSSQL_EXPORT +# endif +#elif defined(LIBODB_MSSQL_SHARED_BUILD) // Building shared. +# ifdef _WIN32 +# define LIBODB_MSSQL_EXPORT __declspec(dllexport) +# else +# define LIBODB_MSSQL_EXPORT +# endif +#else +// If none of the above macros are defined, then we assume we are being used +// by some third-party build system that cannot/doesn't signal the library +// type. Note that this fallback works for both static and shared but in case +// of shared will be sub-optimal compared to having dllimport. +// +# define LIBODB_MSSQL_EXPORT // Using static or shared. +#endif + +#else // LIBODB_MSSQL_BUILD2 + +#ifdef LIBODB_MSSQL_STATIC_LIB +# define LIBODB_MSSQL_EXPORT +#else +# ifdef _WIN32 +# ifdef _MSC_VER +# ifdef LIBODB_MSSQL_DYNAMIC_LIB +# define LIBODB_MSSQL_EXPORT __declspec(dllexport) +# else +# define LIBODB_MSSQL_EXPORT __declspec(dllimport) +# endif +# else +# ifdef LIBODB_MSSQL_DYNAMIC_LIB +# ifdef DLL_EXPORT +# define LIBODB_MSSQL_EXPORT __declspec(dllexport) +# else +# define LIBODB_MSSQL_EXPORT +# endif +# else +# define LIBODB_MSSQL_EXPORT __declspec(dllimport) +# endif +# endif +# else +# define LIBODB_MSSQL_EXPORT +# endif +#endif + +#endif // LIBODB_MSSQL_BUILD2 + +#include + +#endif // ODB_MSSQL_DETAILS_EXPORT_HXX diff --git a/libodb-mssql/odb/mssql/details/options.cli b/libodb-mssql/odb/mssql/details/options.cli new file mode 100644 index 0000000..dcf92e5 --- /dev/null +++ b/libodb-mssql/odb/mssql/details/options.cli @@ -0,0 +1,63 @@ +// file : odb/mssql/details/options.cli +// license : ODB NCUEL; see accompanying LICENSE file + +include ; + +namespace odb +{ + namespace mssql + { + namespace details + { + class options + { + std::string --user | -U + { + "", + "SQL Server database user. If not specified, then Windows + authentication is used." + }; + + std::string --password | -P + { + "", + "SQL Server database password. Omit this option if the user + password is blank or Windows authentication is used." + }; + + std::string --database | -d + { + "", + "SQL Server database name. If not specified, then the default + database for this user is used." + }; + + std::string --server | -S + { + "", + "SQL Server instance address in the + \c{[\i{protocol}\b{:}]\i{host}[\b{\\}\i{instance}][\b{,}\i{port}]} + format, where \ci{protocol} can be \cb{tcp} (TCP/IP), + \cb{lpc} (shared memory), or \cb{np} (named pipe). If not specifid, + then \cb{localhost} is used." + }; + + std::string --driver + { + "", + "SQL Server Native Client ODBC driver name. If not specified, then + the latest available driver is used." + }; + + std::string --options-file + { + "", + "Read additional options from . Each option should appear on a + separate line optionally followed by space or equal sign (\cb{=}) + and an option value. Empty lines and lines starting with \cb{#} are + ignored." + }; + }; + } + } +} diff --git a/libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.cxx b/libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.cxx new file mode 100644 index 0000000..905beb8 --- /dev/null +++ b/libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.cxx @@ -0,0 +1,1125 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +// Begin prologue. +// +// +// End prologue. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace odb +{ + namespace mssql + { + namespace details + { + namespace cli + { + // unknown_option + // + unknown_option:: + ~unknown_option () throw () + { + } + + void unknown_option:: + print (::std::ostream& os) const + { + os << "unknown option '" << option ().c_str () << "'"; + } + + const char* unknown_option:: + what () const throw () + { + return "unknown option"; + } + + // unknown_argument + // + unknown_argument:: + ~unknown_argument () throw () + { + } + + void unknown_argument:: + print (::std::ostream& os) const + { + os << "unknown argument '" << argument ().c_str () << "'"; + } + + const char* unknown_argument:: + what () const throw () + { + return "unknown argument"; + } + + // missing_value + // + missing_value:: + ~missing_value () throw () + { + } + + void missing_value:: + print (::std::ostream& os) const + { + os << "missing value for option '" << option ().c_str () << "'"; + } + + const char* missing_value:: + what () const throw () + { + return "missing option value"; + } + + // invalid_value + // + invalid_value:: + ~invalid_value () throw () + { + } + + void invalid_value:: + print (::std::ostream& os) const + { + os << "invalid value '" << value ().c_str () << "' for option '" + << option ().c_str () << "'"; + + if (!message ().empty ()) + os << ": " << message ().c_str (); + } + + const char* invalid_value:: + what () const throw () + { + return "invalid option value"; + } + + // eos_reached + // + void eos_reached:: + print (::std::ostream& os) const + { + os << what (); + } + + const char* eos_reached:: + what () const throw () + { + return "end of argument stream reached"; + } + + // file_io_failure + // + file_io_failure:: + ~file_io_failure () throw () + { + } + + void file_io_failure:: + print (::std::ostream& os) const + { + os << "unable to open file '" << file ().c_str () << "' or read failure"; + } + + const char* file_io_failure:: + what () const throw () + { + return "unable to open file or read failure"; + } + + // unmatched_quote + // + unmatched_quote:: + ~unmatched_quote () throw () + { + } + + void unmatched_quote:: + print (::std::ostream& os) const + { + os << "unmatched quote in argument '" << argument ().c_str () << "'"; + } + + const char* unmatched_quote:: + what () const throw () + { + return "unmatched quote"; + } + + // scanner + // + scanner:: + ~scanner () + { + } + + // argv_scanner + // + bool argv_scanner:: + more () + { + return i_ < argc_; + } + + const char* argv_scanner:: + peek () + { + if (i_ < argc_) + return argv_[i_]; + else + throw eos_reached (); + } + + const char* argv_scanner:: + next () + { + if (i_ < argc_) + { + const char* r (argv_[i_]); + + if (erase_) + { + for (int i (i_ + 1); i < argc_; ++i) + argv_[i - 1] = argv_[i]; + + --argc_; + argv_[argc_] = 0; + } + else + ++i_; + + ++start_position_; + return r; + } + else + throw eos_reached (); + } + + void argv_scanner:: + skip () + { + if (i_ < argc_) + { + ++i_; + ++start_position_; + } + else + throw eos_reached (); + } + + std::size_t argv_scanner:: + position () + { + return start_position_; + } + + // argv_file_scanner + // + int argv_file_scanner::zero_argc_ = 0; + std::string argv_file_scanner::empty_string_; + + bool argv_file_scanner:: + more () + { + if (!args_.empty ()) + return true; + + while (base::more ()) + { + // See if the next argument is the file option. + // + const char* a (base::peek ()); + const option_info* oi = 0; + const char* ov = 0; + + if (!skip_) + { + if ((oi = find (a)) != 0) + { + base::next (); + + if (!base::more ()) + throw missing_value (a); + + ov = base::next (); + } + else if (std::strncmp (a, "-", 1) == 0) + { + if ((ov = std::strchr (a, '=')) != 0) + { + std::string o (a, 0, ov - a); + if ((oi = find (o.c_str ())) != 0) + { + base::next (); + ++ov; + } + } + } + } + + if (oi != 0) + { + if (oi->search_func != 0) + { + std::string f (oi->search_func (ov, oi->arg)); + + if (!f.empty ()) + load (f); + } + else + load (ov); + + if (!args_.empty ()) + return true; + } + else + { + if (!skip_) + skip_ = (std::strcmp (a, "--") == 0); + + return true; + } + } + + return false; + } + + const char* argv_file_scanner:: + peek () + { + if (!more ()) + throw eos_reached (); + + return args_.empty () ? base::peek () : args_.front ().value.c_str (); + } + + const std::string& argv_file_scanner:: + peek_file () + { + if (!more ()) + throw eos_reached (); + + return args_.empty () ? empty_string_ : *args_.front ().file; + } + + std::size_t argv_file_scanner:: + peek_line () + { + if (!more ()) + throw eos_reached (); + + return args_.empty () ? 0 : args_.front ().line; + } + + const char* argv_file_scanner:: + next () + { + if (!more ()) + throw eos_reached (); + + if (args_.empty ()) + return base::next (); + else + { + hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value); + args_.pop_front (); + ++start_position_; + return hold_[i_].c_str (); + } + } + + void argv_file_scanner:: + skip () + { + if (!more ()) + throw eos_reached (); + + if (args_.empty ()) + return base::skip (); + else + { + args_.pop_front (); + ++start_position_; + } + } + + const argv_file_scanner::option_info* argv_file_scanner:: + find (const char* a) const + { + for (std::size_t i (0); i < options_count_; ++i) + if (std::strcmp (a, options_[i].option) == 0) + return &options_[i]; + + return 0; + } + + std::size_t argv_file_scanner:: + position () + { + return start_position_; + } + + void argv_file_scanner:: + load (const std::string& file) + { + using namespace std; + + ifstream is (file.c_str ()); + + if (!is.is_open ()) + throw file_io_failure (file); + + files_.push_back (file); + + arg a; + a.file = &*files_.rbegin (); + + for (a.line = 1; !is.eof (); ++a.line) + { + string line; + getline (is, line); + + if (is.fail () && !is.eof ()) + throw file_io_failure (file); + + string::size_type n (line.size ()); + + // Trim the line from leading and trailing whitespaces. + // + if (n != 0) + { + const char* f (line.c_str ()); + const char* l (f + n); + + const char* of (f); + while (f < l && (*f == ' ' || *f == '\t' || *f == '\r')) + ++f; + + --l; + + const char* ol (l); + while (l > f && (*l == ' ' || *l == '\t' || *l == '\r')) + --l; + + if (f != of || l != ol) + line = f <= l ? string (f, l - f + 1) : string (); + } + + // Ignore empty lines, those that start with #. + // + if (line.empty () || line[0] == '#') + continue; + + string::size_type p (string::npos); + if (line.compare (0, 1, "-") == 0) + { + p = line.find (' '); + + string::size_type q (line.find ('=')); + if (q != string::npos && q < p) + p = q; + } + + string s1; + if (p != string::npos) + { + s1.assign (line, 0, p); + + // Skip leading whitespaces in the argument. + // + if (line[p] == '=') + ++p; + else + { + n = line.size (); + for (++p; p < n; ++p) + { + char c (line[p]); + if (c != ' ' && c != '\t' && c != '\r') + break; + } + } + } + else if (!skip_) + skip_ = (line == "--"); + + string s2 (line, p != string::npos ? p : 0); + + // If the string (which is an option value or argument) is + // wrapped in quotes, remove them. + // + n = s2.size (); + char cf (s2[0]), cl (s2[n - 1]); + + if (cf == '"' || cf == '\'' || cl == '"' || cl == '\'') + { + if (n == 1 || cf != cl) + throw unmatched_quote (s2); + + s2 = string (s2, 1, n - 2); + } + + if (!s1.empty ()) + { + // See if this is another file option. + // + const option_info* oi; + if (!skip_ && (oi = find (s1.c_str ()))) + { + if (s2.empty ()) + throw missing_value (oi->option); + + if (oi->search_func != 0) + { + string f (oi->search_func (s2.c_str (), oi->arg)); + if (!f.empty ()) + load (f); + } + else + { + // If the path of the file being parsed is not simple and the + // path of the file that needs to be loaded is relative, then + // complete the latter using the former as a base. + // +#ifndef _WIN32 + string::size_type p (file.find_last_of ('/')); + bool c (p != string::npos && s2[0] != '/'); +#else + string::size_type p (file.find_last_of ("/\\")); + bool c (p != string::npos && s2[1] != ':'); +#endif + if (c) + s2.insert (0, file, 0, p + 1); + + load (s2); + } + + continue; + } + + a.value = s1; + args_.push_back (a); + } + + a.value = s2; + args_.push_back (a); + } + } + + template + struct parser + { + static void + parse (X& x, bool& xs, scanner& s) + { + using namespace std; + + const char* o (s.next ()); + if (s.more ()) + { + string v (s.next ()); + istringstream is (v); + if (!(is >> x && is.peek () == istringstream::traits_type::eof ())) + throw invalid_value (o, v); + } + else + throw missing_value (o); + + xs = true; + } + }; + + template <> + struct parser + { + static void + parse (bool& x, bool& xs, scanner& s) + { + const char* o (s.next ()); + + if (s.more ()) + { + const char* v (s.next ()); + + if (std::strcmp (v, "1") == 0 || + std::strcmp (v, "true") == 0 || + std::strcmp (v, "TRUE") == 0 || + std::strcmp (v, "True") == 0) + x = true; + else if (std::strcmp (v, "0") == 0 || + std::strcmp (v, "false") == 0 || + std::strcmp (v, "FALSE") == 0 || + std::strcmp (v, "False") == 0) + x = false; + else + throw invalid_value (o, v); + } + else + throw missing_value (o); + + xs = true; + } + }; + + template <> + struct parser + { + static void + parse (std::string& x, bool& xs, scanner& s) + { + const char* o (s.next ()); + + if (s.more ()) + x = s.next (); + else + throw missing_value (o); + + xs = true; + } + }; + + template + struct parser > + { + static void + parse (std::pair& x, bool& xs, scanner& s) + { + x.second = s.position (); + parser::parse (x.first, xs, s); + } + }; + + template + struct parser > + { + static void + parse (std::vector& c, bool& xs, scanner& s) + { + X x; + bool dummy; + parser::parse (x, dummy, s); + c.push_back (x); + xs = true; + } + }; + + template + struct parser > + { + static void + parse (std::set& c, bool& xs, scanner& s) + { + X x; + bool dummy; + parser::parse (x, dummy, s); + c.insert (x); + xs = true; + } + }; + + template + struct parser > + { + static void + parse (std::map& m, bool& xs, scanner& s) + { + const char* o (s.next ()); + + if (s.more ()) + { + std::size_t pos (s.position ()); + std::string ov (s.next ()); + std::string::size_type p = ov.find ('='); + + K k = K (); + V v = V (); + std::string kstr (ov, 0, p); + std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ())); + + int ac (2); + char* av[] = + { + const_cast (o), + 0 + }; + + bool dummy; + if (!kstr.empty ()) + { + av[1] = const_cast (kstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser::parse (k, dummy, s); + } + + if (!vstr.empty ()) + { + av[1] = const_cast (vstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser::parse (v, dummy, s); + } + + m[k] = v; + } + else + throw missing_value (o); + + xs = true; + } + }; + + template + struct parser > + { + static void + parse (std::multimap& m, bool& xs, scanner& s) + { + const char* o (s.next ()); + + if (s.more ()) + { + std::size_t pos (s.position ()); + std::string ov (s.next ()); + std::string::size_type p = ov.find ('='); + + K k = K (); + V v = V (); + std::string kstr (ov, 0, p); + std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ())); + + int ac (2); + char* av[] = + { + const_cast (o), + 0 + }; + + bool dummy; + if (!kstr.empty ()) + { + av[1] = const_cast (kstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser::parse (k, dummy, s); + } + + if (!vstr.empty ()) + { + av[1] = const_cast (vstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser::parse (v, dummy, s); + } + + m.insert (typename std::multimap::value_type (k, v)); + } + else + throw missing_value (o); + + xs = true; + } + }; + + template + void + thunk (X& x, scanner& s) + { + parser::parse (x.*M, s); + } + + template + void + thunk (X& x, scanner& s) + { + s.next (); + x.*M = true; + } + + template + void + thunk (X& x, scanner& s) + { + parser::parse (x.*M, x.*S, s); + } + } + } + } +} + +#include + +namespace odb +{ + namespace mssql + { + namespace details + { + // options + // + + options:: + options () + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + server_ (), + server_specified_ (false), + driver_ (), + driver_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + } + + options:: + options (int& argc, + char** argv, + bool erase, + ::odb::mssql::details::cli::unknown_mode opt, + ::odb::mssql::details::cli::unknown_mode arg) + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + server_ (), + server_specified_ (false), + driver_ (), + driver_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + ::odb::mssql::details::cli::argv_scanner s (argc, argv, erase); + _parse (s, opt, arg); + } + + options:: + options (int start, + int& argc, + char** argv, + bool erase, + ::odb::mssql::details::cli::unknown_mode opt, + ::odb::mssql::details::cli::unknown_mode arg) + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + server_ (), + server_specified_ (false), + driver_ (), + driver_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + ::odb::mssql::details::cli::argv_scanner s (start, argc, argv, erase); + _parse (s, opt, arg); + } + + options:: + options (int& argc, + char** argv, + int& end, + bool erase, + ::odb::mssql::details::cli::unknown_mode opt, + ::odb::mssql::details::cli::unknown_mode arg) + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + server_ (), + server_specified_ (false), + driver_ (), + driver_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + ::odb::mssql::details::cli::argv_scanner s (argc, argv, erase); + _parse (s, opt, arg); + end = s.end (); + } + + options:: + options (int start, + int& argc, + char** argv, + int& end, + bool erase, + ::odb::mssql::details::cli::unknown_mode opt, + ::odb::mssql::details::cli::unknown_mode arg) + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + server_ (), + server_specified_ (false), + driver_ (), + driver_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + ::odb::mssql::details::cli::argv_scanner s (start, argc, argv, erase); + _parse (s, opt, arg); + end = s.end (); + } + + options:: + options (::odb::mssql::details::cli::scanner& s, + ::odb::mssql::details::cli::unknown_mode opt, + ::odb::mssql::details::cli::unknown_mode arg) + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + server_ (), + server_specified_ (false), + driver_ (), + driver_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + _parse (s, opt, arg); + } + + ::odb::mssql::details::cli::usage_para options:: + print_usage (::std::ostream& os, ::odb::mssql::details::cli::usage_para p) + { + CLI_POTENTIALLY_UNUSED (os); + + if (p != ::odb::mssql::details::cli::usage_para::none) + os << ::std::endl; + + os << "--user|-U SQL Server database user. If not specified, then Windows" << ::std::endl + << " authentication is used." << ::std::endl; + + os << std::endl + << "--password|-P SQL Server database password. Omit this option if the" << ::std::endl + << " user password is blank or Windows authentication is used." << ::std::endl; + + os << std::endl + << "--database|-d SQL Server database name. If not specified, then the" << ::std::endl + << " default database for this user is used." << ::std::endl; + + os << std::endl + << "--server|-S SQL Server instance address in the" << ::std::endl + << " [protocol:]host[\\instance][,port] format, where protocol" << ::std::endl + << " can be tcp (TCP/IP), lpc (shared memory), or np (named" << ::std::endl + << " pipe). If not specifid, then localhost is used." << ::std::endl; + + os << std::endl + << "--driver SQL Server Native Client ODBC driver name. If not" << ::std::endl + << " specified, then the latest available driver is used." << ::std::endl; + + os << std::endl + << "--options-file Read additional options from . Each option should" << ::std::endl + << " appear on a separate line optionally followed by space or" << ::std::endl + << " equal sign (=) and an option value. Empty lines and lines" << ::std::endl + << " starting with # are ignored." << ::std::endl; + + p = ::odb::mssql::details::cli::usage_para::option; + + return p; + } + + typedef + std::map + _cli_options_map; + + static _cli_options_map _cli_options_map_; + + struct _cli_options_map_init + { + _cli_options_map_init () + { + _cli_options_map_["--user"] = + &::odb::mssql::details::cli::thunk< options, std::string, &options::user_, + &options::user_specified_ >; + _cli_options_map_["-U"] = + &::odb::mssql::details::cli::thunk< options, std::string, &options::user_, + &options::user_specified_ >; + _cli_options_map_["--password"] = + &::odb::mssql::details::cli::thunk< options, std::string, &options::password_, + &options::password_specified_ >; + _cli_options_map_["-P"] = + &::odb::mssql::details::cli::thunk< options, std::string, &options::password_, + &options::password_specified_ >; + _cli_options_map_["--database"] = + &::odb::mssql::details::cli::thunk< options, std::string, &options::database_, + &options::database_specified_ >; + _cli_options_map_["-d"] = + &::odb::mssql::details::cli::thunk< options, std::string, &options::database_, + &options::database_specified_ >; + _cli_options_map_["--server"] = + &::odb::mssql::details::cli::thunk< options, std::string, &options::server_, + &options::server_specified_ >; + _cli_options_map_["-S"] = + &::odb::mssql::details::cli::thunk< options, std::string, &options::server_, + &options::server_specified_ >; + _cli_options_map_["--driver"] = + &::odb::mssql::details::cli::thunk< options, std::string, &options::driver_, + &options::driver_specified_ >; + _cli_options_map_["--options-file"] = + &::odb::mssql::details::cli::thunk< options, std::string, &options::options_file_, + &options::options_file_specified_ >; + } + }; + + static _cli_options_map_init _cli_options_map_init_; + + bool options:: + _parse (const char* o, ::odb::mssql::details::cli::scanner& s) + { + _cli_options_map::const_iterator i (_cli_options_map_.find (o)); + + if (i != _cli_options_map_.end ()) + { + (*(i->second)) (*this, s); + return true; + } + + return false; + } + + bool options:: + _parse (::odb::mssql::details::cli::scanner& s, + ::odb::mssql::details::cli::unknown_mode opt_mode, + ::odb::mssql::details::cli::unknown_mode arg_mode) + { + bool r = false; + bool opt = true; + + while (s.more ()) + { + const char* o = s.peek (); + + if (std::strcmp (o, "--") == 0) + { + opt = false; + s.skip (); + r = true; + continue; + } + + if (opt) + { + if (_parse (o, s)) + { + r = true; + continue; + } + + if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0') + { + // Handle combined option values. + // + std::string co; + if (const char* v = std::strchr (o, '=')) + { + co.assign (o, 0, v - o); + ++v; + + int ac (2); + char* av[] = + { + const_cast (co.c_str ()), + const_cast (v) + }; + + ::odb::mssql::details::cli::argv_scanner ns (0, ac, av); + + if (_parse (co.c_str (), ns)) + { + // Parsed the option but not its value? + // + if (ns.end () != 2) + throw ::odb::mssql::details::cli::invalid_value (co, v); + + s.next (); + r = true; + continue; + } + else + { + // Set the unknown option and fall through. + // + o = co.c_str (); + } + } + + switch (opt_mode) + { + case ::odb::mssql::details::cli::unknown_mode::skip: + { + s.skip (); + r = true; + continue; + } + case ::odb::mssql::details::cli::unknown_mode::stop: + { + break; + } + case ::odb::mssql::details::cli::unknown_mode::fail: + { + throw ::odb::mssql::details::cli::unknown_option (o); + } + } + + break; + } + } + + switch (arg_mode) + { + case ::odb::mssql::details::cli::unknown_mode::skip: + { + s.skip (); + r = true; + continue; + } + case ::odb::mssql::details::cli::unknown_mode::stop: + { + break; + } + case ::odb::mssql::details::cli::unknown_mode::fail: + { + throw ::odb::mssql::details::cli::unknown_argument (o); + } + } + + break; + } + + return r; + } + } + } +} + +// Begin epilogue. +// +// +// End epilogue. + diff --git a/libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.hxx b/libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.hxx new file mode 100644 index 0000000..104395b --- /dev/null +++ b/libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.hxx @@ -0,0 +1,562 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +#ifndef LIBODB_MSSQL_DETAILS_OPTIONS_HXX +#define LIBODB_MSSQL_DETAILS_OPTIONS_HXX + +// Begin prologue. +// +// +// End prologue. + +#include +#include +#include +#include +#include +#include + +#ifndef CLI_POTENTIALLY_UNUSED +# if defined(_MSC_VER) || defined(__xlC__) +# define CLI_POTENTIALLY_UNUSED(x) (void*)&x +# else +# define CLI_POTENTIALLY_UNUSED(x) (void)x +# endif +#endif + +namespace odb +{ + namespace mssql + { + namespace details + { + namespace cli + { + class usage_para + { + public: + enum value + { + none, + text, + option + }; + + usage_para (value); + + operator value () const + { + return v_; + } + + private: + value v_; + }; + + class unknown_mode + { + public: + enum value + { + skip, + stop, + fail + }; + + unknown_mode (value); + + operator value () const + { + return v_; + } + + private: + value v_; + }; + + // Exceptions. + // + + class exception: public std::exception + { + public: + virtual void + print (::std::ostream&) const = 0; + }; + + ::std::ostream& + operator<< (::std::ostream&, const exception&); + + class unknown_option: public exception + { + public: + virtual + ~unknown_option () throw (); + + unknown_option (const std::string& option); + + const std::string& + option () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string option_; + }; + + class unknown_argument: public exception + { + public: + virtual + ~unknown_argument () throw (); + + unknown_argument (const std::string& argument); + + const std::string& + argument () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string argument_; + }; + + class missing_value: public exception + { + public: + virtual + ~missing_value () throw (); + + missing_value (const std::string& option); + + const std::string& + option () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string option_; + }; + + class invalid_value: public exception + { + public: + virtual + ~invalid_value () throw (); + + invalid_value (const std::string& option, + const std::string& value, + const std::string& message = std::string ()); + + const std::string& + option () const; + + const std::string& + value () const; + + const std::string& + message () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string option_; + std::string value_; + std::string message_; + }; + + class eos_reached: public exception + { + public: + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + }; + + class file_io_failure: public exception + { + public: + virtual + ~file_io_failure () throw (); + + file_io_failure (const std::string& file); + + const std::string& + file () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string file_; + }; + + class unmatched_quote: public exception + { + public: + virtual + ~unmatched_quote () throw (); + + unmatched_quote (const std::string& argument); + + const std::string& + argument () const; + + virtual void + print (::std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string argument_; + }; + + // Command line argument scanner interface. + // + // The values returned by next() are guaranteed to be valid + // for the two previous arguments up until a call to a third + // peek() or next(). + // + // The position() function returns a monotonically-increasing + // number which, if stored, can later be used to determine the + // relative position of the argument returned by the following + // call to next(). Note that if multiple scanners are used to + // extract arguments from multiple sources, then the end + // position of the previous scanner should be used as the + // start position of the next. + // + class scanner + { + public: + virtual + ~scanner (); + + virtual bool + more () = 0; + + virtual const char* + peek () = 0; + + virtual const char* + next () = 0; + + virtual void + skip () = 0; + + virtual std::size_t + position () = 0; + }; + + class argv_scanner: public scanner + { + public: + argv_scanner (int& argc, + char** argv, + bool erase = false, + std::size_t start_position = 0); + + argv_scanner (int start, + int& argc, + char** argv, + bool erase = false, + std::size_t start_position = 0); + + int + end () const; + + virtual bool + more (); + + virtual const char* + peek (); + + virtual const char* + next (); + + virtual void + skip (); + + virtual std::size_t + position (); + + protected: + std::size_t start_position_; + int i_; + int& argc_; + char** argv_; + bool erase_; + }; + + class argv_file_scanner: public argv_scanner + { + public: + argv_file_scanner (int& argc, + char** argv, + const std::string& option, + bool erase = false, + std::size_t start_position = 0); + + argv_file_scanner (int start, + int& argc, + char** argv, + const std::string& option, + bool erase = false, + std::size_t start_position = 0); + + argv_file_scanner (const std::string& file, + const std::string& option, + std::size_t start_position = 0); + + struct option_info + { + // If search_func is not NULL, it is called, with the arg + // value as the second argument, to locate the options file. + // If it returns an empty string, then the file is ignored. + // + const char* option; + std::string (*search_func) (const char*, void* arg); + void* arg; + }; + + argv_file_scanner (int& argc, + char** argv, + const option_info* options, + std::size_t options_count, + bool erase = false, + std::size_t start_position = 0); + + argv_file_scanner (int start, + int& argc, + char** argv, + const option_info* options, + std::size_t options_count, + bool erase = false, + std::size_t start_position = 0); + + argv_file_scanner (const std::string& file, + const option_info* options = 0, + std::size_t options_count = 0, + std::size_t start_position = 0); + + virtual bool + more (); + + virtual const char* + peek (); + + virtual const char* + next (); + + virtual void + skip (); + + virtual std::size_t + position (); + + // Return the file path if the peeked at argument came from a file and + // the empty string otherwise. The reference is guaranteed to be valid + // till the end of the scanner lifetime. + // + const std::string& + peek_file (); + + // Return the 1-based line number if the peeked at argument came from + // a file and zero otherwise. + // + std::size_t + peek_line (); + + private: + const option_info* + find (const char*) const; + + void + load (const std::string& file); + + typedef argv_scanner base; + + const std::string option_; + option_info option_info_; + const option_info* options_; + std::size_t options_count_; + + struct arg + { + std::string value; + const std::string* file; + std::size_t line; + }; + + std::deque args_; + std::list files_; + + // Circular buffer of two arguments. + // + std::string hold_[2]; + std::size_t i_; + + bool skip_; + + static int zero_argc_; + static std::string empty_string_; + }; + + template + struct parser; + } + } + } +} + +#include + +namespace odb +{ + namespace mssql + { + namespace details + { + class options + { + public: + options (); + + options (int& argc, + char** argv, + bool erase = false, + ::odb::mssql::details::cli::unknown_mode option = ::odb::mssql::details::cli::unknown_mode::fail, + ::odb::mssql::details::cli::unknown_mode argument = ::odb::mssql::details::cli::unknown_mode::stop); + + options (int start, + int& argc, + char** argv, + bool erase = false, + ::odb::mssql::details::cli::unknown_mode option = ::odb::mssql::details::cli::unknown_mode::fail, + ::odb::mssql::details::cli::unknown_mode argument = ::odb::mssql::details::cli::unknown_mode::stop); + + options (int& argc, + char** argv, + int& end, + bool erase = false, + ::odb::mssql::details::cli::unknown_mode option = ::odb::mssql::details::cli::unknown_mode::fail, + ::odb::mssql::details::cli::unknown_mode argument = ::odb::mssql::details::cli::unknown_mode::stop); + + options (int start, + int& argc, + char** argv, + int& end, + bool erase = false, + ::odb::mssql::details::cli::unknown_mode option = ::odb::mssql::details::cli::unknown_mode::fail, + ::odb::mssql::details::cli::unknown_mode argument = ::odb::mssql::details::cli::unknown_mode::stop); + + options (::odb::mssql::details::cli::scanner&, + ::odb::mssql::details::cli::unknown_mode option = ::odb::mssql::details::cli::unknown_mode::fail, + ::odb::mssql::details::cli::unknown_mode argument = ::odb::mssql::details::cli::unknown_mode::stop); + + // Option accessors. + // + const std::string& + user () const; + + bool + user_specified () const; + + const std::string& + password () const; + + bool + password_specified () const; + + const std::string& + database () const; + + bool + database_specified () const; + + const std::string& + server () const; + + bool + server_specified () const; + + const std::string& + driver () const; + + bool + driver_specified () const; + + const std::string& + options_file () const; + + bool + options_file_specified () const; + + // Print usage information. + // + static ::odb::mssql::details::cli::usage_para + print_usage (::std::ostream&, + ::odb::mssql::details::cli::usage_para = ::odb::mssql::details::cli::usage_para::none); + + // Implementation details. + // + protected: + bool + _parse (const char*, ::odb::mssql::details::cli::scanner&); + + private: + bool + _parse (::odb::mssql::details::cli::scanner&, + ::odb::mssql::details::cli::unknown_mode option, + ::odb::mssql::details::cli::unknown_mode argument); + + public: + std::string user_; + bool user_specified_; + std::string password_; + bool password_specified_; + std::string database_; + bool database_specified_; + std::string server_; + bool server_specified_; + std::string driver_; + bool driver_specified_; + std::string options_file_; + bool options_file_specified_; + }; + } + } +} + +#include + +// Begin epilogue. +// +// +// End epilogue. + +#endif // LIBODB_MSSQL_DETAILS_OPTIONS_HXX diff --git a/libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.ixx b/libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.ixx new file mode 100644 index 0000000..a406dc4 --- /dev/null +++ b/libodb-mssql/odb/mssql/details/pregenerated/odb/mssql/details/options.ixx @@ -0,0 +1,372 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +// Begin prologue. +// +// +// End prologue. + +#include + +namespace odb +{ + namespace mssql + { + namespace details + { + namespace cli + { + // usage_para + // + inline usage_para:: + usage_para (value v) + : v_ (v) + { + } + + // unknown_mode + // + inline unknown_mode:: + unknown_mode (value v) + : v_ (v) + { + } + + // exception + // + inline ::std::ostream& + operator<< (::std::ostream& os, const exception& e) + { + e.print (os); + return os; + } + + // unknown_option + // + inline unknown_option:: + unknown_option (const std::string& option) + : option_ (option) + { + } + + inline const std::string& unknown_option:: + option () const + { + return option_; + } + + // unknown_argument + // + inline unknown_argument:: + unknown_argument (const std::string& argument) + : argument_ (argument) + { + } + + inline const std::string& unknown_argument:: + argument () const + { + return argument_; + } + + // missing_value + // + inline missing_value:: + missing_value (const std::string& option) + : option_ (option) + { + } + + inline const std::string& missing_value:: + option () const + { + return option_; + } + + // invalid_value + // + inline invalid_value:: + invalid_value (const std::string& option, + const std::string& value, + const std::string& message) + : option_ (option), + value_ (value), + message_ (message) + { + } + + inline const std::string& invalid_value:: + option () const + { + return option_; + } + + inline const std::string& invalid_value:: + value () const + { + return value_; + } + + inline const std::string& invalid_value:: + message () const + { + return message_; + } + + // file_io_failure + // + inline file_io_failure:: + file_io_failure (const std::string& file) + : file_ (file) + { + } + + inline const std::string& file_io_failure:: + file () const + { + return file_; + } + + // unmatched_quote + // + inline unmatched_quote:: + unmatched_quote (const std::string& argument) + : argument_ (argument) + { + } + + inline const std::string& unmatched_quote:: + argument () const + { + return argument_; + } + + // argv_scanner + // + inline argv_scanner:: + argv_scanner (int& argc, + char** argv, + bool erase, + std::size_t sp) + : start_position_ (sp + 1), + i_ (1), + argc_ (argc), + argv_ (argv), + erase_ (erase) + { + } + + inline argv_scanner:: + argv_scanner (int start, + int& argc, + char** argv, + bool erase, + std::size_t sp) + : start_position_ (sp + static_cast (start)), + i_ (start), + argc_ (argc), + argv_ (argv), + erase_ (erase) + { + } + + inline int argv_scanner:: + end () const + { + return i_; + } + + // argv_file_scanner + // + inline argv_file_scanner:: + argv_file_scanner (int& argc, + char** argv, + const std::string& option, + bool erase, + std::size_t sp) + : argv_scanner (argc, argv, erase, sp), + option_ (option), + options_ (&option_info_), + options_count_ (1), + i_ (1), + skip_ (false) + { + option_info_.option = option_.c_str (); + option_info_.search_func = 0; + } + + inline argv_file_scanner:: + argv_file_scanner (int start, + int& argc, + char** argv, + const std::string& option, + bool erase, + std::size_t sp) + : argv_scanner (start, argc, argv, erase, sp), + option_ (option), + options_ (&option_info_), + options_count_ (1), + i_ (1), + skip_ (false) + { + option_info_.option = option_.c_str (); + option_info_.search_func = 0; + } + + inline argv_file_scanner:: + argv_file_scanner (const std::string& file, + const std::string& option, + std::size_t sp) + : argv_scanner (0, zero_argc_, 0, sp), + option_ (option), + options_ (&option_info_), + options_count_ (1), + i_ (1), + skip_ (false) + { + option_info_.option = option_.c_str (); + option_info_.search_func = 0; + + load (file); + } + + inline argv_file_scanner:: + argv_file_scanner (int& argc, + char** argv, + const option_info* options, + std::size_t options_count, + bool erase, + std::size_t sp) + : argv_scanner (argc, argv, erase, sp), + options_ (options), + options_count_ (options_count), + i_ (1), + skip_ (false) + { + } + + inline argv_file_scanner:: + argv_file_scanner (int start, + int& argc, + char** argv, + const option_info* options, + std::size_t options_count, + bool erase, + std::size_t sp) + : argv_scanner (start, argc, argv, erase, sp), + options_ (options), + options_count_ (options_count), + i_ (1), + skip_ (false) + { + } + + inline argv_file_scanner:: + argv_file_scanner (const std::string& file, + const option_info* options, + std::size_t options_count, + std::size_t sp) + : argv_scanner (0, zero_argc_, 0, sp), + options_ (options), + options_count_ (options_count), + i_ (1), + skip_ (false) + { + load (file); + } + } + } + } +} + +namespace odb +{ + namespace mssql + { + namespace details + { + // options + // + + inline const std::string& options:: + user () const + { + return this->user_; + } + + inline bool options:: + user_specified () const + { + return this->user_specified_; + } + + inline const std::string& options:: + password () const + { + return this->password_; + } + + inline bool options:: + password_specified () const + { + return this->password_specified_; + } + + inline const std::string& options:: + database () const + { + return this->database_; + } + + inline bool options:: + database_specified () const + { + return this->database_specified_; + } + + inline const std::string& options:: + server () const + { + return this->server_; + } + + inline bool options:: + server_specified () const + { + return this->server_specified_; + } + + inline const std::string& options:: + driver () const + { + return this->driver_; + } + + inline bool options:: + driver_specified () const + { + return this->driver_specified_; + } + + inline const std::string& options:: + options_file () const + { + return this->options_file_; + } + + inline bool options:: + options_file_specified () const + { + return this->options_file_specified_; + } + } + } +} + +// Begin epilogue. +// +// +// End epilogue. diff --git a/libodb-mssql/odb/mssql/error.cxx b/libodb-mssql/odb/mssql/error.cxx new file mode 100644 index 0000000..897d415 --- /dev/null +++ b/libodb-mssql/odb/mssql/error.cxx @@ -0,0 +1,273 @@ +// file : odb/mssql/error.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include +#include // std::strlen + +#include +#include +#include +#include + +using namespace std; + +namespace odb +{ + namespace mssql + { + static void + translate_error (SQLRETURN r, + SQLHANDLE h, + SQLSMALLINT htype, + connection* conn, + bool end_tran, + size_t pos, + multiple_exceptions* mex) + { + // First see if we have one of the errors indicated via the + // return error code. + // + switch (r) + { + case SQL_STILL_EXECUTING: + { + throw database_exception (0, "?????", "statement still executing"); + break; + } + case SQL_NEED_DATA: + case SQL_NO_DATA: +#if ODBCVER >= 0x0380 + case SQL_PARAM_DATA_AVAILABLE: +#endif + { + throw database_exception ( + 0, "?????", "unhandled SQL_*_DATA condition"); + break; + } + case SQL_INVALID_HANDLE: + { + throw database_exception (0, "?????", "invalid handle"); + break; + } + } + + // Otherwise the diagnostics is stored in the handle. + // + char sqlstate[SQL_SQLSTATE_SIZE + 1]; + SQLINTEGER native_code; // Will be 0 if no natve code. + char msg[512]; // Will be truncated if doesn't fit. + SQLSMALLINT msg_size; + + // We need to translate certain sqlstate codes to special exceptions, + // such as deadlock, timeout, etc. The problem is we can have multiple + // records potentially with different sqlstate codes. If we have both, + // say, a deadlock code and some other code, then we should probably + // throw database_exception, which is more severe. To implement this + // we are going to pre-scan the records looking for the codes we are + // interested in. If in the process we see any other code, then we + // stop and go ahead to prepare and throw database_exception. + // + enum code + { + code_none, + code_deadlock, + code_timeout, + code_connection_lost + }; + + code c (code_none); + + for (SQLSMALLINT i (1);; ++i) + { + r = SQLGetDiagRecA (htype, + h, + i, + (SQLCHAR*) sqlstate, + &native_code, + 0, + 0, + &msg_size); + + if (r == SQL_NO_DATA) + break; + else if (SQL_SUCCEEDED (r)) + { + code nc; + string s (sqlstate); + + if (s == "40001") // Serialization failure (native code 1205). + nc = code_deadlock; + else if (s == "HYT00") // Timeout expired. + nc = code_timeout; + else if (s == "HYT01") // Connection timeout expired. + { + nc = code_timeout; + + if (conn != 0) + conn->mark_failed (); + } + else if (s == "08S01") // Link failure. + { + nc = code_connection_lost; + + if (conn != 0) + conn->mark_failed (); + } + else if (s == "01000") // General warning. + continue; + else + { + c = code_none; + break; + } + + // If a call to SQLEndTran() fails, then the connection is + // put into the so called "suspended state" and should be + // disconnected unless we know the transaction was rolled + // back. See SQLEndTran() documentation for details. + // + if (end_tran && + s != "25S03" && // Transaction is rolled back. + s != "40001" && // Serialization failure. + s != "40002" && // Integrity constraint. + s != "HYC00") // Optional feature not implemented. + conn->mark_failed (); + + if (c != code_none && c != nc) + { + // Several different codes. + // + c = code_none; + break; + } + + c = nc; + } + else + { + c = code_none; + break; + } + } + + switch (c) + { + case code_deadlock: + throw deadlock (); + case code_timeout: + throw timeout (); + case code_connection_lost: + throw connection_lost (); + case code_none: + break; + } + + // Some other error code. Prepare database_exception. + // + database_exception e; + + for (SQLSMALLINT i (1);; ++i) + { + // If this is for a batch, filter out based on row association. + // Here we only ignore records that have the associated row + // number and this number doesn't match ours. In particular, + // this means that all the un-associated records which will be + // duplicated for all the failed rows, which seems like the + // correct thing to do. + // + if (mex != 0) + { + SQLLEN n; + r = SQLGetDiagField (htype, + h, + i, + SQL_DIAG_ROW_NUMBER, + &n, + 0, + 0); + + if (r == SQL_NO_DATA) + break; + else if (SQL_SUCCEEDED (r) && + n != SQL_NO_ROW_NUMBER && + n != SQL_ROW_NUMBER_UNKNOWN && + n != static_cast (pos + 1)) // 1-based + continue; + } + + r = SQLGetDiagRecA (htype, + h, + i, + (SQLCHAR*) sqlstate, + &native_code, + (SQLCHAR*) msg, + sizeof (msg), + &msg_size); + + if (r == SQL_NO_DATA) + break; + else if (SQL_SUCCEEDED (r)) + { + if (conn != 0) + { + string s (sqlstate); + + if (s == "08S01" || // Link failure. + s == "HYT01" || // Connection timeout. + (end_tran && + s != "25S03" && + s != "40001" && + s != "40002" && + s != "HYC00")) + conn->mark_failed (); + } + + // Get rid of a trailing newline if there is one. + // + size_t n (strlen (msg)); + if (n != 0 && msg[n - 1] == '\n') + msg[n - 1] = '\0'; + + e.append (native_code, sqlstate, msg); + } + else + e.append (0, "?????", "unable to extract information for this " + "diagnostic record"); + } + + if (e.size () == 0) + e.append (0, "?????", "no diagnostic record (using wrong handle?)"); + + if (mex == 0) + throw e; + else + // It could be that some of these errors are fatal. I guess we + // will just have to learn from experience which ones are. The + // client code can always treat specific error codes as fatal. + // + mex->insert (pos, e); + } + + void + translate_error (SQLRETURN r, connection& c, bool end_tran) + { + translate_error (r, c.handle (), SQL_HANDLE_DBC, &c, end_tran, 0, 0); + } + + void + translate_error (SQLRETURN r, + connection& c, + const auto_handle& h, + size_t pos, + multiple_exceptions* mex) + { + translate_error (r, h, SQL_HANDLE_STMT, &c, false, pos, mex); + } + + void + translate_error (SQLRETURN r, SQLHANDLE h, SQLSMALLINT htype) + { + translate_error (r, h, htype, 0, false, 0, 0); + } + } +} diff --git a/libodb-mssql/odb/mssql/error.hxx b/libodb-mssql/odb/mssql/error.hxx new file mode 100644 index 0000000..cb8cc7c --- /dev/null +++ b/libodb-mssql/odb/mssql/error.hxx @@ -0,0 +1,40 @@ +// file : odb/mssql/error.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_ERROR_HXX +#define ODB_MSSQL_ERROR_HXX + +#include +#include // std::size_t + +#include +#include +#include // connection, multiple_exceptions +#include + +#include + +namespace odb +{ + namespace mssql + { + // Translate ODBC error given a handle and throw (or return, in case + // multiple_exceptions is not NULL) an appropriate exception. + // + LIBODB_MSSQL_EXPORT void + translate_error (SQLRETURN, connection&, bool end_tran = false); + + LIBODB_MSSQL_EXPORT void + translate_error (SQLRETURN, + connection&, + const auto_handle&, + std::size_t pos = 0, multiple_exceptions* = 0); + + LIBODB_MSSQL_EXPORT void + translate_error (SQLRETURN, SQLHANDLE, SQLSMALLINT htype); + } +} + +#include + +#endif // ODB_MSSQL_ERROR_HXX diff --git a/libodb-mssql/odb/mssql/exceptions.cxx b/libodb-mssql/odb/mssql/exceptions.cxx new file mode 100644 index 0000000..606678d --- /dev/null +++ b/libodb-mssql/odb/mssql/exceptions.cxx @@ -0,0 +1,109 @@ +// file : odb/mssql/exceptions.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +#include + +using namespace std; + +namespace odb +{ + namespace mssql + { + // + // database_exception + // + + database_exception::record:: + record (SQLINTEGER e, const string& s, const string& m) + : error_ (e), sqlstate_ (s), message_ (m) + { + } + + database_exception:: + ~database_exception () ODB_NOTHROW_NOEXCEPT + { + } + + database_exception:: + database_exception () + { + } + + database_exception:: + database_exception (SQLINTEGER e, const string& s, const string& m) + { + append (e, s, m); + } + + void database_exception:: + append (SQLINTEGER e, const string& s, const string& m) + { + records_.push_back (record (e, s, m)); + + if (!what_.empty ()) + what_ += '\n'; + + ostringstream ostr; + ostr << e << " (" << s << "): " << m; + what_ += ostr.str (); + } + + const char* database_exception:: + what () const ODB_NOTHROW_NOEXCEPT + { + return what_.c_str (); + } + + database_exception* database_exception:: + clone () const + { + return new database_exception (*this); + } + + // + // cli_exception + // + + cli_exception:: + cli_exception (const string& what) + : what_ (what) + { + } + + cli_exception:: + ~cli_exception () ODB_NOTHROW_NOEXCEPT + { + } + + const char* cli_exception:: + what () const ODB_NOTHROW_NOEXCEPT + { + return what_.c_str (); + } + + cli_exception* cli_exception:: + clone () const + { + return new cli_exception (*this); + } + + // + // long_data_reload + // + + const char* long_data_reload:: + what () const ODB_NOTHROW_NOEXCEPT + { + return "attempt to re-load object or view with long data " + "from query result"; + } + + long_data_reload* long_data_reload:: + clone () const + { + return new long_data_reload (*this); + } + } +} diff --git a/libodb-mssql/odb/mssql/exceptions.hxx b/libodb-mssql/odb/mssql/exceptions.hxx new file mode 100644 index 0000000..5240d8d --- /dev/null +++ b/libodb-mssql/odb/mssql/exceptions.hxx @@ -0,0 +1,138 @@ +// file : odb/mssql/exceptions.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_EXCEPTIONS_HXX +#define ODB_MSSQL_EXCEPTIONS_HXX + +#include + +#include +#include + +#include +#include // ODB_NOTHROW_NOEXCEPT + +#include +#include +#include +#include + +namespace odb +{ + namespace mssql + { + struct LIBODB_MSSQL_EXPORT database_exception: odb::database_exception + { + struct record + { + record (SQLINTEGER error, + const std::string& sqlstate, + const std::string& message); + + SQLINTEGER + error () const + { + return error_; + } + + const std::string& + sqlstate () const + { + return sqlstate_; + } + + const std::string& + message () const + { + return message_; + } + + private: + SQLINTEGER error_; + std::string sqlstate_; + std::string message_; + }; + + typedef std::vector records; + + typedef records::size_type size_type; + typedef records::const_iterator iterator; + + iterator + begin () const + { + return records_.begin (); + } + + iterator + end () const + { + return records_.end (); + } + + size_type + size () const + { + return records_.size (); + } + + virtual const char* + what () const ODB_NOTHROW_NOEXCEPT; + + virtual database_exception* + clone () const; + + public: + ~database_exception () ODB_NOTHROW_NOEXCEPT; + + database_exception (); + database_exception (SQLINTEGER error, + const std::string& sqlstate, + const std::string& message); + + void + append (SQLINTEGER error, + const std::string& sqlstate, + const std::string& message); + + private: + records records_; + std::string what_; + }; + + struct LIBODB_MSSQL_EXPORT cli_exception: odb::exception + { + cli_exception (const std::string& what); + ~cli_exception () ODB_NOTHROW_NOEXCEPT; + + virtual const char* + what () const ODB_NOTHROW_NOEXCEPT; + + virtual cli_exception* + clone () const; + + private: + std::string what_; + }; + + struct LIBODB_MSSQL_EXPORT long_data_reload: odb::exception + { + virtual const char* + what () const ODB_NOTHROW_NOEXCEPT; + + virtual long_data_reload* + clone () const; + }; + + namespace core + { + using mssql::database_exception; + using mssql::cli_exception; + using mssql::long_data_reload; + } + } +} + +#include + +#endif // ODB_MSSQL_EXCEPTIONS_HXX diff --git a/libodb-mssql/odb/mssql/forward.hxx b/libodb-mssql/odb/mssql/forward.hxx new file mode 100644 index 0000000..4f32b22 --- /dev/null +++ b/libodb-mssql/odb/mssql/forward.hxx @@ -0,0 +1,91 @@ +// file : odb/mssql/forward.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_FORWARD_HXX +#define ODB_MSSQL_FORWARD_HXX + +#include + +#include + +namespace odb +{ + namespace mssql + { + namespace core + { + using namespace odb::common; + } + + // + // + class database; + class connection; + typedef details::shared_ptr connection_ptr; + class connection_factory; + class statement; + class transaction; + class tracer; + + namespace core + { + using mssql::database; + using mssql::connection; + using mssql::connection_ptr; + using mssql::transaction; + using mssql::statement; + } + + // Implementation details. + // + enum statement_kind + { + statement_select, + statement_insert, + statement_update, + statement_delete + }; + + class binding; + class select_statement; + + template + class object_statements; + + template + class polymorphic_root_object_statements; + + template + class polymorphic_derived_object_statements; + + template + class no_id_object_statements; + + template + class view_statements; + + template + class container_statements; + + template + class smart_container_statements; + + template + class section_statements; + + class query_base; + } + + namespace details + { + template <> + struct counter_type + { + typedef shared_base counter; + }; + } +} + +#include + +#endif // ODB_MSSQL_FORWARD_HXX diff --git a/libodb-mssql/odb/mssql/mssql-fwd.hxx b/libodb-mssql/odb/mssql/mssql-fwd.hxx new file mode 100644 index 0000000..44ac428 --- /dev/null +++ b/libodb-mssql/odb/mssql/mssql-fwd.hxx @@ -0,0 +1,216 @@ +// file : odb/mssql/mssql-fwd.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_MSSQL_FWD_HXX +#define ODB_MSSQL_MSSQL_FWD_HXX + +#include + +#include // std::size_t + +// Forward declaration for some of the types defined in sqltypes.h or +// sqlncli.h. This allows us to avoid having to include these files +// in public headers. +// +#ifdef _WIN32 + +// Keep consistent with Windows ODBC headers. +// + +typedef long SQLINTEGER; +typedef unsigned long SQLUINTEGER; + +#ifdef _WIN64 +typedef __int64 SQLLEN; +typedef unsigned __int64 SQLULEN; +#else +#ifndef SQLLEN +typedef SQLINTEGER SQLLEN; +typedef SQLUINTEGER SQLULEN; +#endif +#endif + +#else // _WIN32 + +// Keep consistent with unixODBC headers. +// + +template +struct odbc_types; + +template <> +struct odbc_types<4> +{ + typedef long integer; + typedef unsigned long uinteger; + + typedef integer len; + typedef uinteger ulen; +}; + +template <> +struct odbc_types<8> +{ + typedef int integer; + typedef unsigned int uinteger; + + typedef long len; + typedef unsigned long ulen; +}; + +typedef odbc_types::integer SQLINTEGER; +typedef odbc_types::uinteger SQLUINTEGER; + +#ifndef SQLLEN +typedef odbc_types::len SQLLEN; +typedef odbc_types::ulen SQLULEN; +#endif + +#endif // _WIN32 + +typedef short SQLSMALLINT; +typedef unsigned short SQLUSMALLINT; + +typedef SQLSMALLINT SQLRETURN; + +typedef void* SQLHANDLE; +typedef SQLHANDLE SQLHENV; +typedef SQLHANDLE SQLHDBC; +typedef SQLHANDLE SQLHSTMT; +typedef SQLHANDLE SQLHDESC; + +// If you get a redefinition error or warning for one of these macros, +// then that means you included this header (or one that includes it), +// before or . As a general rule, include or +// before any of the ODB headers. +// +#ifndef SQL_HANDLE_ENV +# define SQL_HANDLE_ENV 1 +# define SQL_HANDLE_DBC 2 +# define SQL_HANDLE_STMT 3 +# define SQL_HANDLE_DESC 4 +#endif + +#ifndef SQL_NULL_DATA +# define SQL_NULL_DATA (-1) +# define SQL_DATA_AT_EXEC (-2) +# define SQL_NO_TOTAL (-4) +#endif + +// The following types are our own equivalents of ODBC and Native Client +// ODBC driver types. They are all PODs and should be layout-compatible +// with the original types, which means they can be used interchangeably. +// +namespace odb +{ + namespace mssql + { + // UCS-2 character type (SQLWCHAR). + // +#ifdef _WIN32 + typedef wchar_t ucs2_char; +#else + typedef unsigned short ucs2_char; +#endif + + // SQL_NUMERIC_STRUCT + // +#ifndef SQL_MAX_NUMERIC_LEN +#define SQL_MAX_NUMERIC_LEN 16 +#else +# if SQL_MAX_NUMERIC_LEN != 16 +# error unexpected SQL_NUMERIC_STRUCT value +# endif +#endif + + struct decimal + { + unsigned char precision; + signed char scale; + unsigned char sign; // 1 - positive, 0 - negative + unsigned char val[SQL_MAX_NUMERIC_LEN]; + }; + + // DBMONEY + // + struct money + { + // 8-byte signed integer containing value * 10,000. + // + int high; + unsigned int low; + }; + + // DBMONEY4 + // + struct smallmoney + { + int value; // 4-byte signed integer containing value * 10,000. + }; + + // SQL_DATE_STRUCT + // + struct date + { + SQLSMALLINT year; + SQLUSMALLINT month; + SQLUSMALLINT day; + }; + + // SQL_SS_TIME2_STRUCT + // +#pragma pack(push,8) + struct time + { + SQLUSMALLINT hour; + SQLUSMALLINT minute; + SQLUSMALLINT second; + SQLUINTEGER fraction; + }; +#pragma pack(pop) + + // SQL_TIMESTAMP_STRUCT + // + struct datetime + { + SQLSMALLINT year; + SQLUSMALLINT month; + SQLUSMALLINT day; + SQLUSMALLINT hour; + SQLUSMALLINT minute; + SQLUSMALLINT second; + SQLUINTEGER fraction; + }; + + // SQL_SS_TIMESTAMPOFFSET_STRUCT + // +#pragma pack(push,8) + struct datetimeoffset + { + SQLSMALLINT year; + SQLUSMALLINT month; + SQLUSMALLINT day; + SQLUSMALLINT hour; + SQLUSMALLINT minute; + SQLUSMALLINT second; + SQLUINTEGER fraction; + SQLSMALLINT timezone_hour; + SQLSMALLINT timezone_minute; + }; +#pragma pack(pop) + + // SQLGUID + // + struct uniqueidentifier + { + unsigned int data1; + unsigned short data2; + unsigned short data3; + unsigned char data4[8]; + }; + } +} + +#include + +#endif // ODB_MSSQL_MSSQL_FWD_HXX diff --git a/libodb-mssql/odb/mssql/mssql-types.hxx b/libodb-mssql/odb/mssql/mssql-types.hxx new file mode 100644 index 0000000..b07aeb6 --- /dev/null +++ b/libodb-mssql/odb/mssql/mssql-types.hxx @@ -0,0 +1,161 @@ +// file : odb/mssql/mssql-types.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_MSSQL_TYPES_HXX +#define ODB_MSSQL_MSSQL_TYPES_HXX + +#include + +#include // std::size_t + +#include +#include + +namespace odb +{ + namespace mssql + { + enum chunk_type + { + chunk_null, + chunk_one, + chunk_first, + chunk_next, + chunk_last, + }; + + typedef void (*param_callback_type) ( + const void* context, // User context. + std::size_t* position, // Position context. An implementation is free + // to use this to track position information. It + // is initialized to zero before the first call. + const void** buffer, // [in/out] Buffer contaning the data. On the + // the first call it contains a pointer to the + // long_callback struct (used for redirections). + std::size_t* size, // [out] Data size. + chunk_type*, // [out] The position of this chunk of data. + void* temp_buffer, // A temporary buffer that may be used by the + // implementation. + std::size_t capacity); // Capacity of the temporary buffer. + + typedef void (*result_callback_type) ( + void* context, // User context. + std::size_t* position, // Position context. An implementation is free + // to use this to track position information. It + // is initialized to zero before the first call. + void** buffer, // [in/out] Buffer to copy the data to. On the + // the first call it contains a pointer to the + // long_callback struct (used for redirections). + std::size_t* size, // [in/out] In: amount of data copied into the + // buffer after the previous call. Out: capacity + // of the buffer. + chunk_type, // The position of this chunk; chunk_first means + // this is the first call, chunk_last means there + // is no more data, chunk_null means this value is + // NULL, and chunk_one means the value is empty. + std::size_t size_left, // Contains the amount of data left or 0 if this + // information is not available. + void* temp_buffer, // A temporary buffer that may be used by the + // implementation. + std::size_t capacity); // Capacity of the temporary buffer. + + struct long_callback + { + union + { + param_callback_type param; + result_callback_type result; + } callback; + + union + { + const void* param; + void* result; + } context; + }; + + struct bind + { + // This enumeration identifies the possible buffer types that can be + // bound to a parameter or result. In most cases, these map directly + // to SQL_XXX/SQL_C_XXX codes. + // + enum buffer_type + { + bit, // Buffer is a 1-byte integer. + tinyint, // Buffer is a 1-byte integer. + smallint, // Buffer is a 2-byte integer. + int_, // Buffer is a 4-byte integer. + bigint, // Buffer is an 8-byte integer. + + decimal, // Buffer is a decimal struct (SQL_NUMERIC_STRUCT). + + smallmoney, // Buffer is a smallmoney struct (DBMONEY4). + money, // Buffer is a money struct (DBMONEY). + + float4, // Buffer is a float. + float8, // Buffer is a double. + + string, // Buffer is a char array. + long_string, // Buffer is a long_callback. + + nstring, // Buffer is a ucs2_char array. + long_nstring, // Buffer is a long_callback. + + binary, // Buffer is a byte array. + long_binary, // Buffer is a long_callback. + + date, // Buffer is a date struct (SQL_DATE_STRUCT). + time, // Buffer is a time struct (SQL_SS_TIME2_STRUCT). + datetime, // Buffer is a datetime struct + // (SQL_TIMESTAMP_STRUCT). + datetimeoffset, // Buffer is a datetimeoffset + // (SQL_SS_TIMESTAMPOFFSET_STRUCT). + + uniqueidentifier, // Buffer is a uniqueidentifier struct (SQLGUID). + rowversion, // Buffer is an 8-byte array. + + last // Used as an end of list marker. + }; + + buffer_type type; // The buffer type. + void* buffer; // The buffer. For long data this is a long_callback. + SQLLEN* size_ind; // Pointer to the size/inidicator variable. Size is + // ignored except for variable-size, [small]money, and + // rowversion types. Sepcial indicator values are + // SQL_NULL_DATA (value is NULL) and SQL_DATA_AT_EXEC + // (should be set for the long_* data types). + SQLLEN capacity; // Buffer capacity. Only used for variable-size + // types as well as to pass column/size precisions + // as follows: For string/binary parameters this + // value (minus one character for strings) is used + // as maximum column size. For decimal parameters + // it contains precision (p) and scale (s) encoded + // as (p * 100 + s). For float4 and float8 it + // contains precision. For time, datetime, and + // datatimeoffset it contains fractional seconds + // (scale). In case of datetime, the special + // value 8 indicates the SMALLDATETIME type + // which has no seconds. + }; + + // An instance of this structure specifies the function to invoke and + // the context to pass when the object/view image is about to be + // modified. This mechanism is used by the query machinery to save the + // image between result iteration and dereferencing if something gets + // executed between these two operations that would overwrite the + // image. + // + struct change_callback + { + change_callback (): callback (0), context (0) {}; + + void (*callback) (void*); + void* context; + }; + } +} + +#include + +#endif // ODB_MSSQL_MSSQL_TYPES_HXX diff --git a/libodb-mssql/odb/mssql/mssql.hxx b/libodb-mssql/odb/mssql/mssql.hxx new file mode 100644 index 0000000..b0d2355 --- /dev/null +++ b/libodb-mssql/odb/mssql/mssql.hxx @@ -0,0 +1,69 @@ +// file : odb/mssql/mssql.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_MSSQL_HXX +#define ODB_MSSQL_MSSQL_HXX + +#include + +// This file should always be included before mssql-fwd.hxx. +// +#ifdef ODB_MSSQL_MSSQL_FWD_HXX +# error odb/mssql/mssql-fwd.hxx included before odb/mssql/mssql.hxx +#endif + +#ifdef _WIN32 +# include +#endif + +#include // Standard ODBC. + +//#define _SQLNCLI_ODBC_ +//#include // SQL Server Native Client driver specifics. + +// Instead of having a dependency on (which, BTW, is not +// currently available for the Linux version of the Native Client), +// we are going to provide the few definitions that we need ourselves. +// +#ifndef SQL_SS_LENGTH_UNLIMITED +# define SQL_SS_LENGTH_UNLIMITED 0 +#endif + +#ifndef SQL_COPT_SS_BASE +# define SQL_COPT_SS_BASE 1200 +#endif + +#ifndef SQL_COPT_SS_MARS_ENABLED +# define SQL_COPT_SS_MARS_ENABLED (SQL_COPT_SS_BASE + 24) +#endif + +#ifndef SQL_MARS_ENABLED_NO +# define SQL_MARS_ENABLED_NO 0L +# define SQL_MARS_ENABLED_YES 1L +#endif + +#ifndef SQL_COPT_SS_TXN_ISOLATION +# define SQL_COPT_SS_TXN_ISOLATION (SQL_COPT_SS_BASE + 27) +#endif + +#ifndef SQL_TXN_SS_SNAPSHOT +# define SQL_TXN_SS_SNAPSHOT 0x00000020L +#endif + +#ifndef SQL_SS_TIME2 +# define SQL_SS_TIME2 (-154) +# define SQL_SS_TIMESTAMPOFFSET (-155) +#endif + +// unixODBC doesn't define SQL_PARAM_DATA_AVAILABLE even though it +// claims ODBC version 3.80. +// +#if ODBCVER >= 0x0380 +# ifndef SQL_PARAM_DATA_AVAILABLE +# define SQL_PARAM_DATA_AVAILABLE 101 +# endif +#endif + +#include + +#endif // ODB_MSSQL_MSSQL_HXX diff --git a/libodb-mssql/odb/mssql/no-id-object-result.hxx b/libodb-mssql/odb/mssql/no-id-object-result.hxx new file mode 100644 index 0000000..ad674bc --- /dev/null +++ b/libodb-mssql/odb/mssql/no-id-object-result.hxx @@ -0,0 +1,85 @@ +// file : odb/mssql/no-id-object-result.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_NO_ID_OBJECT_RESULT_HXX +#define ODB_MSSQL_NO_ID_OBJECT_RESULT_HXX + +#include + +#include // std::size_t + +#include +#include + +#include + +#include +#include // query_base +#include +#include + +namespace odb +{ + namespace mssql + { + template + class no_id_object_result_impl: public odb::no_id_object_result_impl + { + public: + typedef odb::no_id_object_result_impl base_type; + + typedef typename base_type::object_type object_type; + typedef typename base_type::pointer_type pointer_type; + + typedef object_traits_impl object_traits; + typedef typename base_type::pointer_traits pointer_traits; + + typedef typename object_traits::statements_type statements_type; + + virtual + ~no_id_object_result_impl (); + + no_id_object_result_impl (const query_base&, + details::shared_ptr, + statements_type&, + const schema_version_migration*); + + virtual void + load (object_type&); + + virtual void + next (); + + virtual void + cache (); + + virtual std::size_t + size (); + + virtual void + invalidate (); + + using base_type::current; + + private: + typedef mssql::change_callback change_callback_type; + + static void + change_callback (void* context); + + private: + details::shared_ptr statement_; + statements_type& statements_; + object_traits_calls tc_; + bool can_load_; + bool use_copy_; + typename object_traits::image_type* image_copy_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_NO_ID_OBJECT_RESULT_HXX diff --git a/libodb-mssql/odb/mssql/no-id-object-result.txx b/libodb-mssql/odb/mssql/no-id-object-result.txx new file mode 100644 index 0000000..06b7d15 --- /dev/null +++ b/libodb-mssql/odb/mssql/no-id-object-result.txx @@ -0,0 +1,154 @@ +// file : odb/mssql/no-id-object-result.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include +#include // result_not_cached + +#include // long_data_reload +#include + +namespace odb +{ + namespace mssql + { + template + no_id_object_result_impl:: + ~no_id_object_result_impl () + { + invalidate (); + } + + template + void no_id_object_result_impl:: + invalidate () + { + change_callback_type& cc (statements_.image ().change_callback_); + + if (cc.context == this) + { + cc.callback = 0; + cc.context = 0; + } + + delete image_copy_; + image_copy_ = 0; + + if (!this->end_) + { + statement_->free_result (); + this->end_ = true; + } + + statement_.reset (); + } + + template + no_id_object_result_impl:: + no_id_object_result_impl (const query_base&, + details::shared_ptr statement, + statements_type& statements, + const schema_version_migration* svm) + : base_type (statements.connection ()), + statement_ (statement), + statements_ (statements), + tc_ (svm), + use_copy_ (false), + image_copy_ (0) + { + } + + template + void no_id_object_result_impl:: + load (object_type& obj) + { + if (!can_load_) + throw long_data_reload (); + + object_traits::callback (this->db_, obj, callback_event::pre_load); + + tc_.init (obj, + use_copy_ ? *image_copy_ : statements_.image (), + &this->db_); + + // If we are using a copy, make sure the callback information for + // long data also comes from the copy. + // + can_load_ = !statement_->stream_result ( + use_copy_ ? &statements_.image () : 0, + use_copy_ ? image_copy_ : 0); + + object_traits::callback (this->db_, obj, callback_event::post_load); + } + + template + void no_id_object_result_impl:: + next () + { + can_load_ = true; + this->current (pointer_type ()); + + typename object_traits::image_type& im (statements_.image ()); + change_callback_type& cc (im.change_callback_); + + if (cc.context == this) + { + cc.callback = 0; + cc.context = 0; + } + + use_copy_ = false; + + if (im.version != statements_.select_image_version ()) + { + binding& b (statements_.select_image_binding ()); + tc_.bind (b.bind, im, statement_select); + statements_.select_image_version (im.version); + b.version++; + } + + if (statement_->fetch () == select_statement::no_data) + { + statement_->free_result (); + this->end_ = true; + } + else + { + cc.callback = &change_callback; + cc.context = this; + } + } + + template + void no_id_object_result_impl:: + cache () + { + } + + template + std::size_t no_id_object_result_impl:: + size () + { + throw result_not_cached (); + } + + template + void no_id_object_result_impl:: + change_callback (void* c) + { + no_id_object_result_impl* r ( + static_cast*> (c)); + + typename object_traits::image_type im (r->statements_.image ()); + + if (r->image_copy_ == 0) + r->image_copy_ = new typename object_traits::image_type (im); + else + *r->image_copy_ = im; + + im.change_callback_.callback = 0; + im.change_callback_.context = 0; + + r->use_copy_ = true; + } + } +} diff --git a/libodb-mssql/odb/mssql/no-id-object-statements.hxx b/libodb-mssql/odb/mssql/no-id-object-statements.hxx new file mode 100644 index 0000000..8d49355 --- /dev/null +++ b/libodb-mssql/odb/mssql/no-id-object-statements.hxx @@ -0,0 +1,137 @@ +// file : odb/mssql/no-id-object-statements.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_NO_ID_OBJECT_STATEMENTS_HXX +#define ODB_MSSQL_NO_ID_OBJECT_STATEMENTS_HXX + +#include + +#include // std::size_t + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace odb +{ + namespace mssql + { + // + // Implementation for objects without object id. + // + + template + class no_id_object_statements: public statements_base + { + public: + typedef T object_type; + typedef object_traits_impl object_traits; + typedef typename object_traits::pointer_type pointer_type; + typedef typename object_traits::image_type image_type; + + typedef mssql::insert_statement insert_statement_type; + + public: + no_id_object_statements (connection_type&); + + virtual + ~no_id_object_statements (); + + // Object image. + // + image_type& + image (std::size_t i = 0) + { + return image_[i]; + } + + // Insert binding. + // + std::size_t + insert_image_version () const { return insert_image_version_;} + + void + insert_image_version (std::size_t v) {insert_image_version_ = v;} + + binding& + insert_image_binding () {return insert_image_binding_;} + + // Select binding (needed for query support). + // + std::size_t + select_image_version () const { return select_image_version_;} + + void + select_image_version (std::size_t v) {select_image_version_ = v;} + + binding& + select_image_binding () {return select_image_binding_;} + + // Statements. + // + insert_statement_type& + persist_statement () + { + if (persist_ == 0) + persist_.reset ( + new (details::shared) insert_statement_type ( + conn_, + object_traits::persist_statement, + object_traits::versioned, // Process if versioned. + insert_image_binding_, + false, + false, + 0, + false)); + + return *persist_; + } + + public: + // select = total + // insert = total - inverse; inverse == 0 for object without id + // + static const std::size_t insert_column_count = + object_traits::column_count; + + static const std::size_t select_column_count = + object_traits::column_count; + + private: + no_id_object_statements (const no_id_object_statements&); + no_id_object_statements& operator= (const no_id_object_statements&); + + private: + image_type image_[object_traits::batch]; + SQLUSMALLINT status_[object_traits::batch]; + + // Select binding. + // + std::size_t select_image_version_; + binding select_image_binding_; + bind select_image_bind_[select_column_count]; + + // Insert binding. + // + std::size_t insert_image_version_; + binding insert_image_binding_; + bind insert_image_bind_[insert_column_count]; + + details::shared_ptr persist_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_NO_ID_OBJECT_STATEMENTS_HXX diff --git a/libodb-mssql/odb/mssql/no-id-object-statements.txx b/libodb-mssql/odb/mssql/no-id-object-statements.txx new file mode 100644 index 0000000..30cc438 --- /dev/null +++ b/libodb-mssql/odb/mssql/no-id-object-statements.txx @@ -0,0 +1,39 @@ +// file : odb/mssql/no-id-object-statements.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::memset + +namespace odb +{ + namespace mssql + { + template + no_id_object_statements:: + ~no_id_object_statements () + { + } + + template + no_id_object_statements:: + no_id_object_statements (connection_type& conn) + : statements_base (conn), + select_image_binding_ (select_image_bind_, select_column_count), + insert_image_binding_ (insert_image_bind_, + insert_column_count, + object_traits::batch, + sizeof (image_type), + status_) + { + image_[0].version = 0; // Only version in the first element used. + select_image_version_ = 0; + insert_image_version_ = 0; + + // SELECT statements only use the first element (no batches). + // + select_image_binding_.change_callback = image_[0].change_callback (); + + std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); + std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); + } + } +} diff --git a/libodb-mssql/odb/mssql/polymorphic-object-result.hxx b/libodb-mssql/odb/mssql/polymorphic-object-result.hxx new file mode 100644 index 0000000..5ee9642 --- /dev/null +++ b/libodb-mssql/odb/mssql/polymorphic-object-result.hxx @@ -0,0 +1,99 @@ +// file : odb/mssql/polymorphic-object-result.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_POLYMORPHIC_OBJECT_RESULT_HXX +#define ODB_MSSQL_POLYMORPHIC_OBJECT_RESULT_HXX + +#include + +#include // std::size_t + +#include +#include + +#include + +#include +#include // query_base +#include +#include + +namespace odb +{ + namespace mssql + { + template + class polymorphic_object_result_impl: + public odb::polymorphic_object_result_impl + { + public: + typedef odb::polymorphic_object_result_impl base_type; + + typedef typename base_type::id_type id_type; + typedef typename base_type::object_type object_type; + typedef typename base_type::pointer_type pointer_type; + + typedef object_traits_impl object_traits; + typedef typename base_type::pointer_traits pointer_traits; + + typedef typename base_type::root_type root_type; + typedef typename base_type::discriminator_type discriminator_type; + + typedef object_traits_impl root_traits; + + typedef typename object_traits::image_type image_type; + typedef typename object_traits::statements_type statements_type; + + virtual + ~polymorphic_object_result_impl (); + + polymorphic_object_result_impl (const query_base&, + details::shared_ptr, + statements_type&, + const schema_version_migration*); + + virtual void + load (object_type*, bool fetch); + + virtual id_type + load_id (); + + virtual discriminator_type + load_discriminator (); + + virtual void + next (); + + virtual void + cache (); + + virtual std::size_t + size (); + + virtual void + invalidate (); + + using base_type::current; + + private: + typedef mssql::change_callback change_callback_type; + + static void + change_callback (void* context); + + private: + details::shared_ptr statement_; + statements_type& statements_; + object_traits_calls tc_; + bool can_load_; + bool use_copy_; + image_type* image_copy_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_POLYMORPHIC_OBJECT_RESULT_HXX diff --git a/libodb-mssql/odb/mssql/polymorphic-object-result.txx b/libodb-mssql/odb/mssql/polymorphic-object-result.txx new file mode 100644 index 0000000..159010f --- /dev/null +++ b/libodb-mssql/odb/mssql/polymorphic-object-result.txx @@ -0,0 +1,325 @@ +// file : odb/mssql/polymorphic-object-result.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +#include +#include // result_not_cached + +#include // long_data_reload +#include + +namespace odb +{ + namespace mssql + { + template + polymorphic_object_result_impl:: + ~polymorphic_object_result_impl () + { + invalidate (); + } + + template + void polymorphic_object_result_impl:: + invalidate () + { + change_callback_type& cc ( + statements_.root_statements ().image ().change_callback_); + + if (cc.context == this) + { + cc.context = 0; + cc.callback = 0; + } + + if (image_copy_ != 0) + { + object_traits::free_image (image_copy_); + image_copy_ = 0; + } + + if (!this->end_) + { + statement_->free_result (); + this->end_ = true; + } + + statement_.reset (); + } + + template + polymorphic_object_result_impl:: + polymorphic_object_result_impl (const query_base&, + details::shared_ptr st, + statements_type& sts, + const schema_version_migration* svm) + : base_type (sts.connection ()), + statement_ (st), + statements_ (sts), + tc_ (svm), + use_copy_ (false), + image_copy_ (0) + { + } + + template + void polymorphic_object_result_impl:: + load (object_type* pobj, bool) + { + if (!can_load_) + throw long_data_reload (); + + typename statements_type::root_statements_type& rsts ( + statements_.root_statements ()); + + // This is a top-level call so the statements cannot be locked. + // + assert (!rsts.locked ()); + typename statements_type::auto_lock l (rsts); + + image_type& i (use_copy_ ? *image_copy_ : statements_.image ()); + typename root_traits::image_type& ri ( + use_copy_ ? object_traits::root_image (i) : rsts.image ()); + + id_type id (root_traits::id (ri)); + + // Determine this object's dynamic type. + // + typedef typename root_traits::info_type info_type; + discriminator_type d (root_traits::discriminator (ri)); + + // Use the polymorphic_info() helper to get concrete_info if + // object_type is concrete and NULL if it is abstract. + // + const info_type* spi (polymorphic_info (object_traits::info)); + const info_type& pi ( + spi != 0 && spi->discriminator == d + ? *spi + : root_traits::map->find (d)); + + typedef typename root_traits::pointer_type root_pointer_type; + typedef typename root_traits::pointer_traits root_pointer_traits; + + typename object_traits::pointer_cache_traits::insert_guard ig; + + if (pobj == 0) + { + // Need to create a new instance of the dynamic type. + // + root_pointer_type rp (pi.create ()); + pointer_type p ( + root_pointer_traits::template static_pointer_cast (rp)); + + // Insert it as a root pointer (for non-unique pointers, rp should + // still be valid and for unique pointers this is a no-op). + // + ig.reset ( + object_traits::pointer_cache_traits::insert (this->db_, id, rp)); + + pobj = &pointer_traits::get_ref (p); + current (p); + } + else + { + // We are loading into an existing instance. If the static and + // dynamic types differ, then make sure the instance is at least + // of the dynamic type. + // + if (&pi != &object_traits::info) + { + const info_type& dpi (root_traits::map->find (typeid (*pobj))); + + if (&dpi != &pi && dpi.derived (pi)) + throw object_not_persistent (); // @@ type_mismatch ? + } + } + + callback_event ce (callback_event::pre_load); + pi.dispatch (info_type::call_callback, this->db_, pobj, &ce); + + tc_.init (*pobj, i, &this->db_); + + // If we are using a copy, make sure the callback information for + // long data also comes from the copy. + // + can_load_ = !statement_->stream_result ( + use_copy_ ? &statements_.image () : 0, + use_copy_ ? image_copy_ : 0); + + // Initialize the id image and binding and load the rest of the object + // (containers, dynamic part, etc). + // + typename object_traits::id_image_type& idi (statements_.id_image ()); + root_traits::init (idi, id); + + binding& idb (statements_.id_image_binding ()); + if (idi.version != statements_.id_image_version () || idb.version == 0) + { + object_traits::bind (idb.bind, idi); + statements_.id_image_version (idi.version); + idb.version++; + } + + tc_.load_ (statements_, *pobj, false); + + // Load the dynamic part of the object unless static and dynamic + // types are the same. + // + if (&pi != &object_traits::info) + { + std::size_t d (object_traits::depth); + pi.dispatch (info_type::call_load, this->db_, pobj, &d); + }; + + rsts.load_delayed (tc_.version ()); + l.unlock (); + + ce = callback_event::post_load; + pi.dispatch (info_type::call_callback, this->db_, pobj, &ce); + object_traits::pointer_cache_traits::load (ig.position ()); + ig.release (); + } + + template + typename polymorphic_object_result_impl::id_type + polymorphic_object_result_impl:: + load_id () + { + typename root_traits::image_type& i ( + use_copy_ + ? object_traits::root_image (*image_copy_) + : statements_.root_statements ().image ()); + + return root_traits::id (i); + } + + template + typename polymorphic_object_result_impl::discriminator_type + polymorphic_object_result_impl:: + load_discriminator () + { + typename root_traits::image_type& i ( + use_copy_ + ? object_traits::root_image (*image_copy_) + : statements_.root_statements ().image ()); + + return root_traits::discriminator (i); + } + + template + struct polymorphic_image_rebind + { + // Derived type version. + // + typedef object_traits_impl traits; + + static void + rebind (typename traits::statements_type& sts, + const schema_version_migration* svm) + { + typename traits::image_type& im (sts.image ()); + + if (traits::check_version (sts.select_image_versions (), im)) + { + binding& b (sts.select_image_binding (traits::depth)); + object_traits_calls tc (svm); + tc.bind (b.bind, 0, 0, im, statement_select); + traits::update_version ( + sts.select_image_versions (), im, sts.select_image_bindings ()); + } + } + }; + + template + struct polymorphic_image_rebind + { + // Root type version. + // + typedef object_traits_impl traits; + + static void + rebind (typename traits::statements_type& sts, + const schema_version_migration* svm) + { + typename traits::image_type& im (sts.image ()); + + if (im.version != sts.select_image_version ()) + { + binding& b (sts.select_image_binding ()); + object_traits_calls tc (svm); + tc.bind (b.bind, im, statement_select); + sts.select_image_version (im.version); + b.version++; + } + } + }; + + template + void polymorphic_object_result_impl:: + next () + { + can_load_ = true; + this->current (pointer_type ()); + + change_callback_type& cc ( + statements_.root_statements ().image ().change_callback_); + + if (cc.context == this) + { + cc.callback = 0; + cc.context = 0; + } + + use_copy_ = false; + polymorphic_image_rebind::rebind ( + statements_, tc_.version ()); + + if (statement_->fetch () == select_statement::no_data) + { + statement_->free_result (); + this->end_ = true; + } + else + { + cc.callback = &change_callback; + cc.context = this; + } + } + + template + void polymorphic_object_result_impl:: + cache () + { + } + + template + std::size_t polymorphic_object_result_impl:: + size () + { + throw result_not_cached (); + } + + template + void polymorphic_object_result_impl:: + change_callback (void* c) + { + polymorphic_object_result_impl* r ( + static_cast*> (c)); + image_type& im (r->statements_.image ()); + + if (r->image_copy_ == 0) + r->image_copy_ = object_traits::clone_image (im); + else + object_traits::copy_image (*r->image_copy_, im); + + typename root_traits::image_type& rim ( + r->statements_.root_statements ().image ()); + + rim.change_callback_.callback = 0; + rim.change_callback_.context = 0; + + r->use_copy_ = true; + } + } +} diff --git a/libodb-mssql/odb/mssql/polymorphic-object-statements.hxx b/libodb-mssql/odb/mssql/polymorphic-object-statements.hxx new file mode 100644 index 0000000..c115502 --- /dev/null +++ b/libodb-mssql/odb/mssql/polymorphic-object-statements.hxx @@ -0,0 +1,469 @@ +// file : odb/mssql/polymorphic-object-statements.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX +#define ODB_MSSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX + +#include + +#include // std::size_t + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace odb +{ + namespace mssql + { + // + // Implementation for polymorphic objects. + // + + template + class polymorphic_root_object_statements: public object_statements + { + public: + typedef typename object_statements::connection_type connection_type; + typedef typename object_statements::object_traits object_traits; + typedef typename object_statements::id_image_type id_image_type; + + typedef + typename object_traits::discriminator_image_type + discriminator_image_type; + + typedef + typename object_statements::select_statement_type + select_statement_type; + + public: + // Interface compatibility with derived_object_statements. + // + typedef polymorphic_root_object_statements root_statements_type; + + root_statements_type& + root_statements () + { + return *this; + } + + public: + // Discriminator binding. + // + discriminator_image_type& + discriminator_image () {return discriminator_image_;} + + std::size_t + discriminator_image_version () const + {return discriminator_image_version_;} + + void + discriminator_image_version (std::size_t v) + {discriminator_image_version_ = v;} + + binding& + discriminator_image_binding () {return discriminator_image_binding_;} + + // Id binding for discriminator retrieval. + // + id_image_type& + discriminator_id_image () {return discriminator_id_image_;} + + std::size_t + discriminator_id_image_version () const + {return discriminator_id_image_version_;} + + void + discriminator_id_image_version (std::size_t v) + {discriminator_id_image_version_ = v;} + + binding& + discriminator_id_image_binding () + {return discriminator_id_image_binding_;} + + // + // + select_statement_type& + find_discriminator_statement () + { + if (find_discriminator_ == 0) + find_discriminator_.reset ( + new (details::shared) select_statement_type ( + this->conn_, + object_traits::find_discriminator_statement, + false, // Doesn't need to be processed. + false, // Don't optimize. + discriminator_id_image_binding_, + discriminator_image_binding_, + false)); + + return *find_discriminator_; + } + + public: + polymorphic_root_object_statements (connection_type&); + + virtual + ~polymorphic_root_object_statements (); + + // Static "override" (statements type). + // + void + load_delayed (const schema_version_migration* svm) + { + assert (this->locked ()); + + if (!this->delayed_.empty ()) + this->template load_delayed_ ( + svm); + } + + public: + static const std::size_t id_column_count = + object_statements::id_column_count; + + static const std::size_t discriminator_column_count = + object_traits::discriminator_column_count; + + static const std::size_t managed_optimistic_column_count = + object_traits::managed_optimistic_column_count; + + private: + // Discriminator image. + // + discriminator_image_type discriminator_image_; + std::size_t discriminator_image_version_; + binding discriminator_image_binding_; + bind discriminator_image_bind_[discriminator_column_count + + managed_optimistic_column_count]; + + // Id image for discriminator retrieval (only used as a parameter). + // + id_image_type discriminator_id_image_; + std::size_t discriminator_id_image_version_; + binding discriminator_id_image_binding_; + bind discriminator_id_image_bind_[id_column_count]; + + details::shared_ptr find_discriminator_; + }; + + template + class polymorphic_derived_object_statements: public statements_base + { + public: + typedef T object_type; + typedef object_traits_impl object_traits; + typedef typename object_traits::id_type id_type; + typedef typename object_traits::pointer_type pointer_type; + typedef typename object_traits::id_image_type id_image_type; + typedef typename object_traits::image_type image_type; + + typedef typename object_traits::root_type root_type; + typedef + polymorphic_root_object_statements + root_statements_type; + + typedef typename object_traits::base_type base_type; + typedef + typename object_traits::base_traits::statements_type + base_statements_type; + + typedef + typename object_traits::extra_statement_cache_type + extra_statement_cache_type; + + typedef mssql::insert_statement insert_statement_type; + typedef mssql::select_statement select_statement_type; + typedef mssql::update_statement update_statement_type; + typedef mssql::delete_statement delete_statement_type; + + typedef typename root_statements_type::auto_lock auto_lock; + + public: + polymorphic_derived_object_statements (connection_type&); + + virtual + ~polymorphic_derived_object_statements (); + + public: + // Delayed loading. + // + static void + delayed_loader (odb::database&, + const id_type&, + root_type&, + const schema_version_migration*); + + public: + // Root and immediate base statements. + // + root_statements_type& + root_statements () + { + return root_statements_; + } + + base_statements_type& + base_statements () + { + return base_statements_; + } + + public: + // Object image. + // + image_type& + image () + { + return image_; + } + + // Insert binding. + // + std::size_t + insert_image_version () const { return insert_image_version_;} + + void + insert_image_version (std::size_t v) {insert_image_version_ = v;} + + std::size_t + insert_id_binding_version () const { return insert_id_binding_version_;} + + void + insert_id_binding_version (std::size_t v) {insert_id_binding_version_ = v;} + + binding& + insert_image_binding () {return insert_image_binding_;} + + // Update binding. + // + std::size_t + update_image_version () const { return update_image_version_;} + + void + update_image_version (std::size_t v) {update_image_version_ = v;} + + std::size_t + update_id_binding_version () const { return update_id_binding_version_;} + + void + update_id_binding_version (std::size_t v) {update_id_binding_version_ = v;} + + binding& + update_image_binding () {return update_image_binding_;} + + // Select binding. + // + std::size_t* + select_image_versions () { return select_image_versions_;} + + binding* + select_image_bindings () {return select_image_bindings_;} + + binding& + select_image_binding (std::size_t d) + { + return select_image_bindings_[object_traits::depth - d]; + } + + // Object id binding (comes from the root statements). + // + id_image_type& + id_image () {return root_statements_.id_image ();} + + std::size_t + id_image_version () const {return root_statements_.id_image_version ();} + + void + id_image_version (std::size_t v) {root_statements_.id_image_version (v);} + + binding& + id_image_binding () {return root_statements_.id_image_binding ();} + + binding& + optimistic_id_image_binding () { + return root_statements_.optimistic_id_image_binding ();} + + // Statements. + // + insert_statement_type& + persist_statement () + { + // Auto id and version are in the root. + // + if (persist_ == 0) + persist_.reset ( + new (details::shared) insert_statement_type ( + conn_, + object_traits::persist_statement, + object_traits::versioned, // Process if versioned. + insert_image_binding_, + false, + false, + 0)); + + return *persist_; + } + + select_statement_type& + find_statement (std::size_t d) + { + std::size_t i (object_traits::depth - d); + details::shared_ptr& p (find_[i]); + + if (p == 0) + p.reset ( + new (details::shared) select_statement_type ( + conn_, + object_traits::find_statements[i], + object_traits::versioned, // Process if versioned. + false, // Don't optimize. + root_statements_.id_image_binding (), + select_image_bindings_[i], + false)); + + return *p; + } + + update_statement_type& + update_statement () + { + if (update_ == 0) + update_.reset ( + new (details::shared) update_statement_type ( + conn_, + object_traits::update_statement, + object_traits::versioned, // Process if versioned. + update_image_binding_, + 0, + false)); + + return *update_; + } + + delete_statement_type& + erase_statement () + { + if (erase_ == 0) + erase_.reset ( + new (details::shared) delete_statement_type ( + conn_, + object_traits::erase_statement, + root_statements_.id_image_binding (), + false)); + + return *erase_; + } + + // Extra (container, section) statement cache. + // + extra_statement_cache_type& + extra_statement_cache () + { + return extra_statement_cache_.get ( + conn_, + image_, + id_image (), + id_image_binding (), + &id_image_binding ()); // Note, not id+version. + } + + public: + // select = total - id - separate_load + base::select + // insert = total - inverse + // update = total - inverse - id - readonly - separate_update + // + static const std::size_t id_column_count = + object_traits::id_column_count; + + static const std::size_t select_column_count = + object_traits::column_count - + id_column_count - + object_traits::separate_load_column_count + + base_statements_type::select_column_count; + + static const std::size_t insert_column_count = + object_traits::column_count - + object_traits::inverse_column_count; + + static const std::size_t update_column_count = insert_column_count - + object_traits::id_column_count - + object_traits::readonly_column_count - + object_traits::separate_update_column_count; + + private: + polymorphic_derived_object_statements ( + const polymorphic_derived_object_statements&); + + polymorphic_derived_object_statements& + operator= (const polymorphic_derived_object_statements&); + + private: + root_statements_type& root_statements_; + base_statements_type& base_statements_; + + extra_statement_cache_ptr extra_statement_cache_; + + image_type image_; + + // Select binding. Here we are have an array of statements/bindings + // one for each depth. In other words, if we have classes root, base, + // and derived, then we have the following array of statements: + // + // [0] d + b + r + // [1] d + b + // [2] d + // + // Also, because we have a chain of images bound to these statements, + // we have an array of versions, one entry for each base plus one for + // our own image. + // + // A poly-abstract class only needs the first statement and in this + // case we have only one entry in the the bindings and statements + // arrays (but not versions; we still have a chain of images). + // + std::size_t select_image_versions_[object_traits::depth]; + binding select_image_bindings_[ + object_traits::abstract ? 1 : object_traits::depth]; + bind select_image_bind_[select_column_count]; + + // Insert binding. The id binding is copied from the hierarchy root. + // + std::size_t insert_image_version_; + std::size_t insert_id_binding_version_; + binding insert_image_binding_; + bind insert_image_bind_[insert_column_count]; + + // Update binding. The id suffix binding is copied from the hierarchy + // root. + // + std::size_t update_image_version_; + std::size_t update_id_binding_version_; + binding update_image_binding_; + bind update_image_bind_[update_column_count + id_column_count]; + + details::shared_ptr persist_; + details::shared_ptr find_[ + object_traits::abstract ? 1 : object_traits::depth]; + details::shared_ptr update_; + details::shared_ptr erase_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX diff --git a/libodb-mssql/odb/mssql/polymorphic-object-statements.txx b/libodb-mssql/odb/mssql/polymorphic-object-statements.txx new file mode 100644 index 0000000..0ba437a --- /dev/null +++ b/libodb-mssql/odb/mssql/polymorphic-object-statements.txx @@ -0,0 +1,140 @@ +// file : odb/mssql/polymorphic-object-statements.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::memset + +#include +#include + +#include +#include +#include +#include + +namespace odb +{ + namespace mssql + { + // + // polymorphic_root_object_statements + // + + template + polymorphic_root_object_statements:: + ~polymorphic_root_object_statements () + { + } + + template + polymorphic_root_object_statements:: + polymorphic_root_object_statements (connection_type& conn) + : object_statements (conn), + discriminator_image_binding_ (discriminator_image_bind_, + discriminator_column_count + + managed_optimistic_column_count), + discriminator_id_image_binding_ (discriminator_id_image_bind_, + id_column_count) + { + discriminator_image_.version = 0; + discriminator_id_image_.version = 0; + + discriminator_image_version_ = 0; + discriminator_id_image_version_ = 0; + + std::memset ( + discriminator_image_bind_, 0, sizeof (discriminator_image_bind_)); + std::memset ( + discriminator_id_image_bind_, 0, sizeof (discriminator_id_image_bind_)); + } + + // + // polymorphic_derived_object_statements + // + + template + polymorphic_derived_object_statements:: + ~polymorphic_derived_object_statements () + { + } + + template + polymorphic_derived_object_statements:: + polymorphic_derived_object_statements (connection_type& conn) + : statements_base (conn), + root_statements_ (conn.statement_cache ().find_object ()), + base_statements_ (conn.statement_cache ().find_object ()), + insert_image_binding_ (insert_image_bind_, insert_column_count), + update_image_binding_ (update_image_bind_, + update_column_count + id_column_count) + { + image_.base = &base_statements_.image (); + image_.version = 0; + + for (std::size_t i (0); i < object_traits::depth; ++i) + select_image_versions_[i] = 0; + + for (std::size_t i (0); + i < (object_traits::abstract ? 1 : object_traits::depth); + ++i) + { + select_image_bindings_[i].bind = select_image_bind_; + select_image_bindings_[i].count = object_traits::find_column_counts[i]; + select_image_bindings_[i].change_callback = 0; + } + + // Statements other than the first one (which goes all the way to + // the root) can never override the image because they are used to + // load up the dynamic part of the object only after the static + // part has been loaded (and triggered the callback if necessary). + // + select_image_bindings_[0].change_callback = + root_statements_.image ().change_callback (); + + insert_image_version_ = 0; + insert_id_binding_version_ = 0; + update_image_version_ = 0; + update_id_binding_version_ = 0; + + std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); + std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); + std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); + } + + template + void polymorphic_derived_object_statements:: + delayed_loader (odb::database& db, + const id_type& id, + root_type& robj, + const schema_version_migration* svm) + { + connection_type& conn (transaction::current ().connection (db)); + polymorphic_derived_object_statements& sts ( + conn.statement_cache ().find_object ()); + root_statements_type& rsts (sts.root_statements ()); + + object_type& obj (static_cast (robj)); + + // The same code as in object_statements::load_delayed_(). + // + object_traits_calls tc (svm); + + if (!tc.find_ (sts, &id)) + throw object_not_persistent (); + + auto_result ar (*sts.find_[0]); + + object_traits::callback (db, obj, callback_event::pre_load); + tc.init (obj, sts.image (), &db); + sts.find_[0]->stream_result (); + ar.free (); + tc.load_ (sts, obj, false); // Load containers, etc. + + rsts.load_delayed (svm); + + { + typename root_statements_type::auto_unlock u (rsts); + object_traits::callback (db, obj, callback_event::post_load); + } + } + } +} diff --git a/libodb-mssql/odb/mssql/prepared-query.cxx b/libodb-mssql/odb/mssql/prepared-query.cxx new file mode 100644 index 0000000..ae0389d --- /dev/null +++ b/libodb-mssql/odb/mssql/prepared-query.cxx @@ -0,0 +1,15 @@ +// file : odb/mssql/prepared-query.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +namespace odb +{ + namespace mssql + { + prepared_query_impl:: + ~prepared_query_impl () + { + } + } +} diff --git a/libodb-mssql/odb/mssql/prepared-query.hxx b/libodb-mssql/odb/mssql/prepared-query.hxx new file mode 100644 index 0000000..730f7ec --- /dev/null +++ b/libodb-mssql/odb/mssql/prepared-query.hxx @@ -0,0 +1,34 @@ +// file : odb/mssql/prepared-query.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_PREPARED_QUERY_HXX +#define ODB_MSSQL_PREPARED_QUERY_HXX + +#include + +#include + +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + struct LIBODB_MSSQL_EXPORT prepared_query_impl: odb::prepared_query_impl + { + virtual + ~prepared_query_impl (); + + prepared_query_impl (odb::connection& c): odb::prepared_query_impl (c) {} + + mssql::query_base query; + }; + } +} + +#include + +#endif // ODB_MSSQL_PREPARED_QUERY_HXX diff --git a/libodb-mssql/odb/mssql/query-const-expr.cxx b/libodb-mssql/odb/mssql/query-const-expr.cxx new file mode 100644 index 0000000..4e28fad --- /dev/null +++ b/libodb-mssql/odb/mssql/query-const-expr.cxx @@ -0,0 +1,14 @@ +// file : odb/mssql/query-const-expr.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +namespace odb +{ + namespace mssql + { + // Sun CC cannot handle this in query.cxx. + // + const query_base query_base::true_expr (true); + } +} diff --git a/libodb-mssql/odb/mssql/query-dynamic.cxx b/libodb-mssql/odb/mssql/query-dynamic.cxx new file mode 100644 index 0000000..fb49b2b --- /dev/null +++ b/libodb-mssql/odb/mssql/query-dynamic.cxx @@ -0,0 +1,157 @@ +// file : odb/mssql/query-dynamic.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::size_t + +#include + +using namespace std; + +namespace odb +{ + namespace mssql + { + static const char* logic_operators[] = {") AND (", ") OR ("}; + static const char* comp_operators[] = {"=", "!=", "<", ">", "<=", ">="}; + + static void + translate (query_base& q, const odb::query_base& s, size_t p) + { + typedef odb::query_base::clause_part part; + + const part& x (s.clause ()[p]); + + switch (x.kind) + { + case part::kind_column: + { + const query_column_base* c ( + static_cast ( + x.native_info[id_mssql].column)); + + q.append (c->table (), c->column ()); + break; + } + case part::kind_param_val: + case part::kind_param_ref: + { + const query_column_base& qc ( + *static_cast ( + x.native_info[id_mssql].column)); + + query_param_factory f ( + reinterpret_cast ( + x.native_info[id_mssql].param_factory)); + + const odb::query_param* p ( + reinterpret_cast (x.data)); + + q.append (f (p->value, qc, x.kind == part::kind_param_ref), + qc.conversion ()); + break; + } + case part::kind_native: + { + q.append (s.strings ()[x.data]); + break; + } + case part::kind_true: + case part::kind_false: + { + q.append (x.kind == part::kind_true); + break; + } + case part::op_add: + { + translate (q, s, x.data); + translate (q, s, p - 1); + break; + } + case part::op_and: + case part::op_or: + { + q += "("; + translate (q, s, x.data); + q += logic_operators[x.kind - part::op_and]; + translate (q, s, p - 1); + q += ")"; + break; + } + case part::op_not: + { + q += "NOT ("; + translate (q, s, p - 1); + q += ")"; + break; + } + case part::op_null: + case part::op_not_null: + { + translate (q, s, p - 1); + q += (x.kind == part::op_null ? "IS NULL" : "IS NOT NULL"); + break; + } + case part::op_in: + { + if (x.data != 0) + { + size_t b (p - x.data); + + translate (q, s, b - 1); // column + q += "IN ("; + + for (size_t i (b); i != p; ++i) + { + if (i != b) + q += ","; + + translate (q, s, i); + } + + q += ")"; + } + else + q.append (false); + + break; + } + case part::op_like: + { + translate (q, s, p - 2); // column + q += "LIKE"; + translate (q, s, p - 1); // pattern + break; + } + case part::op_like_escape: + { + translate (q, s, p - 3); // column + q += "LIKE"; + translate (q, s, p - 2); // pattern + q += "ESCAPE"; + translate (q, s, p - 1); // escape + break; + } + case part::op_eq: + case part::op_ne: + case part::op_lt: + case part::op_gt: + case part::op_le: + case part::op_ge: + { + translate (q, s, x.data); + q += comp_operators[x.kind - part::op_eq]; + translate (q, s, p - 1); + break; + } + } + } + + query_base:: + query_base (const odb::query_base& q) + : binding_ (0, 0) + { + if (!q.empty ()) + translate (*this, q, q.clause ().size () - 1); + } + } +} diff --git a/libodb-mssql/odb/mssql/query-dynamic.hxx b/libodb-mssql/odb/mssql/query-dynamic.hxx new file mode 100644 index 0000000..ceb423b --- /dev/null +++ b/libodb-mssql/odb/mssql/query-dynamic.hxx @@ -0,0 +1,32 @@ +// file : odb/mssql/query-dynamic.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_QUERY_DYNAMIC_HXX +#define ODB_MSSQL_QUERY_DYNAMIC_HXX + +#include + +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + typedef details::shared_ptr (*query_param_factory) ( + const void* val, const query_column_base&, bool by_ref); + + template + details::shared_ptr + query_param_factory_impl (const void*, const query_column_base&, bool); + } +} + +#include +#include + +#include + +#endif // ODB_MSSQL_QUERY_DYNAMIC_HXX diff --git a/libodb-mssql/odb/mssql/query-dynamic.ixx b/libodb-mssql/odb/mssql/query-dynamic.ixx new file mode 100644 index 0000000..005175f --- /dev/null +++ b/libodb-mssql/odb/mssql/query-dynamic.ixx @@ -0,0 +1,30 @@ +// file : odb/mssql/query-dynamic.ixx +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace mssql + { + // + // + template + inline query_column:: + query_column (odb::query_column& qc, + const char* table, + const char* column, + const char* conv, + unsigned short prec, + unsigned short scale) + : query_column_base (table, column, conv, prec, scale) + { + native_column_info& ci (qc.native_info[id_mssql]); + ci.column = static_cast (this); + + // For some reason GCC needs this statically-typed pointer in + // order to instantiate the functions. + // + query_param_factory f (&query_param_factory_impl); + ci.param_factory = reinterpret_cast (f); + } + } +} diff --git a/libodb-mssql/odb/mssql/query-dynamic.txx b/libodb-mssql/odb/mssql/query-dynamic.txx new file mode 100644 index 0000000..8683c0f --- /dev/null +++ b/libodb-mssql/odb/mssql/query-dynamic.txx @@ -0,0 +1,25 @@ +// file : odb/mssql/query-dynamic.txx +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace mssql + { + template + details::shared_ptr + query_param_factory_impl (const void* val, + const query_column_base& qc, + bool by_ref) + { + const T& v (*static_cast (val)); + + unsigned short p (qc.prec ()); + unsigned short s (qc.scale ()); + + return details::shared_ptr ( + by_ref + ? new (details::shared) query_param_impl (ref_bind (v, p, s)) + : new (details::shared) query_param_impl (val_bind (v, p, s))); + } + } +} diff --git a/libodb-mssql/odb/mssql/query.cxx b/libodb-mssql/odb/mssql/query.cxx new file mode 100644 index 0000000..6dd87e7 --- /dev/null +++ b/libodb-mssql/odb/mssql/query.cxx @@ -0,0 +1,406 @@ +// file : odb/mssql/query.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::size_t +#include // std::memset, std::memcpy + +#include + +using namespace std; + +namespace odb +{ + namespace mssql + { + // query_param + // + query_param:: + ~query_param () + { + } + + // query_base + // + query_base:: + query_base (const query_base& q) + : clause_ (q.clause_), + parameters_ (q.parameters_), + bind_ (q.bind_), + binding_ (0, 0) + { + // Here and below we want to maintain up to date binding info so + // that the call to parameters_binding() below is an immutable + // operation, provided the query does not have any by-reference + // parameters. This way a by-value-only query can be shared + // between multiple threads without the need for synchronization. + // + if (size_t n = bind_.size ()) + { + binding_.bind = &bind_[0]; + binding_.count = n; + binding_.version++; + } + } + + query_base& query_base:: + operator= (const query_base& q) + { + if (this != &q) + { + clause_ = q.clause_; + parameters_ = q.parameters_; + bind_ = q.bind_; + + size_t n (bind_.size ()); + binding_.bind = n != 0 ? &bind_[0] : 0; + binding_.count = n; + binding_.version++; + } + + return *this; + } + + query_base& query_base:: + operator+= (const query_base& q) + { + clause_.insert (clause_.end (), q.clause_.begin (), q.clause_.end ()); + + size_t n (bind_.size ()); + + parameters_.insert ( + parameters_.end (), q.parameters_.begin (), q.parameters_.end ()); + + bind_.insert ( + bind_.end (), q.bind_.begin (), q.bind_.end ()); + + if (n != bind_.size ()) + { + binding_.bind = &bind_[0]; + binding_.count = bind_.size (); + binding_.version++; + } + + return *this; + } + + void query_base:: + append (const string& q) + { + if (!clause_.empty () && + clause_.back ().kind == clause_part::kind_native) + { + string& s (clause_.back ().part); + + char first (!q.empty () ? q[0] : ' '); + char last (!s.empty () ? s[s.size () - 1] : ' '); + + // We don't want extra spaces after '(' as well as before ',' + // and ')'. + // + if (last != ' ' && last != '\n' && last != '(' && + first != ' ' && first != '\n' && first != ',' && first != ')') + s += ' '; + + s += q; + } + else + clause_.push_back (clause_part (clause_part::kind_native, q)); + } + + void query_base:: + append (const char* table, const char* column) + { + string s (table); + s += '.'; + s += column; + + clause_.push_back (clause_part (clause_part::kind_column, s)); + } + + void query_base:: + append (details::shared_ptr p, const char* conv) + { + clause_.push_back (clause_part (clause_part::kind_param)); + + if (conv != 0) + clause_.back ().part = conv; + + parameters_.push_back (p); + bind_.push_back (bind ()); + binding_.bind = &bind_[0]; + binding_.count = bind_.size (); + binding_.version++; + + bind* b (&bind_.back ()); + memset (b, 0, sizeof (bind)); + p->bind (b); + } + + void query_base:: + init_parameters () const + { + bool inc_ver (false); + + for (size_t i (0); i < parameters_.size (); ++i) + { + query_param& p (*parameters_[i]); + + if (p.reference ()) + { + if (p.init ()) + { + p.bind (&bind_[i]); + inc_ver = true; + } + } + } + + if (inc_ver) + binding_.version++; + } + + static bool + check_prefix (const string& s) + { + string::size_type n; + + // It is easier to compare to upper and lower-case versions + // rather than getting involved with the portable case- + // insensitive string comparison mess. + // + if (s.compare (0, (n = 5), "WHERE") == 0 || + s.compare (0, (n = 5), "where") == 0 || + s.compare (0, (n = 6), "SELECT") == 0 || + s.compare (0, (n = 6), "select") == 0 || + s.compare (0, (n = 8), "ORDER BY") == 0 || + s.compare (0, (n = 8), "order by") == 0 || + s.compare (0, (n = 8), "GROUP BY") == 0 || + s.compare (0, (n = 8), "group by") == 0 || + s.compare (0, (n = 6), "HAVING") == 0 || + s.compare (0, (n = 6), "having") == 0 || + s.compare (0, (n = 4), "EXEC") == 0 || + s.compare (0, (n = 4), "exec") == 0 || + s.compare (0, (n = 7), "EXECUTE") == 0 || + s.compare (0, (n = 7), "execute") == 0) + { + // It either has to be an exact match, or there should be + // a whitespace following the keyword. + // + if (s.size () == n || s[n] == ' ' || s[n] == '\n' || s[n] =='\t') + return true; + } + + return false; + } + + void query_base:: + optimize () + { + // Remove a single TRUE literal or one that is followe by one of + // the other clauses. This avoids useless WHERE clauses like + // + // WHERE TRUE GROUP BY foo + // + clause_type::iterator i (clause_.begin ()), e (clause_.end ()); + + if (i != e && i->kind == clause_part::kind_bool && i->bool_part) + { + clause_type::iterator j (i + 1); + + if (j == e || + (j->kind == clause_part::kind_native && check_prefix (j->part))) + clause_.erase (i); + } + } + + const char* query_base:: + clause_prefix () const + { + if (!clause_.empty ()) + { + const clause_part& p (clause_.front ()); + + if (p.kind == clause_part::kind_native && check_prefix (p.part)) + return ""; + + return "WHERE "; + } + + return ""; + } + + string query_base:: + clause () const + { + string r; + + for (clause_type::const_iterator i (clause_.begin ()), + end (clause_.end ()); + i != end; + ++i) + { + char last (!r.empty () ? r[r.size () - 1] : ' '); + + switch (i->kind) + { + case clause_part::kind_column: + { + if (last != ' ' && last != '\n' && last != '(') + r += ' '; + + r += i->part; + break; + } + case clause_part::kind_param: + { + if (last != ' ' && last != '\n' && last != '(') + r += ' '; + + // Add the conversion expression, if any. + // + string::size_type p (0); + if (!i->part.empty ()) + { + p = i->part.find ("(?)"); + r.append (i->part, 0, p); + } + + r += '?'; + + if (!i->part.empty ()) + r.append (i->part, p + 3, string::npos); + + break; + } + case clause_part::kind_native: + { + // We don't want extra spaces after '(' as well as before ',' + // and ')'. + // + const string& p (i->part); + char first (!p.empty () ? p[0] : ' '); + + if (last != ' ' && last != '\n' && last != '(' && + first != ' ' && first != '\n' && first != ',' && first != ')') + r += ' '; + + r += p; + break; + } + case clause_part::kind_bool: + { + if (last != ' ' && last != '\n' && last != '(') + r += ' '; + + // SQL Server does not have "true" TRUE and FALSE boolean + // constants (there seem to be TRUE and FALSE literals but + // they are interpreted as integers). Boolean values seem + // to only be created as the result of boolean expressions. + // + r += i->bool_part ? "1 = 1" : "1 = 0"; + break; + } + } + } + + return clause_prefix () + r; + } + + query_base + operator&& (const query_base& x, const query_base& y) + { + // Optimize cases where one or both sides are constant truth. + // + bool xt (x.const_true ()), yt (y.const_true ()); + + if (xt && yt) + return x; + + if (xt) + return y; + + if (yt) + return x; + + query_base r ("("); + r += x; + r += ") AND ("; + r += y; + r += ")"; + return r; + } + + query_base + operator|| (const query_base& x, const query_base& y) + { + query_base r ("("); + r += x; + r += ") OR ("; + r += y; + r += ")"; + return r; + } + + query_base + operator! (const query_base& x) + { + query_base r ("NOT ("); + r += x; + r += ")"; + return r; + } + + // + // long_query_param_impl + // + + void long_query_param_impl:: + copy () + { + size_ = 0; + + // The below code is the same as in statement.cxx. + // + const void* buf (&callback_); + char tmp_buf[1024]; + + size_t position (0); + for (;;) + { + size_t n; + chunk_type chunk; + + callback_.callback.param ( + callback_.context.param, + &position, + &buf, + &n, + &chunk, + tmp_buf, + sizeof (tmp_buf)); + + if (chunk != chunk_null) + { + if (buf_.capacity () < size_ + n) + buf_.capacity (size_ + n, size_); + + memcpy (buf_.data () + size_, buf, n); + size_ += n; + } + + if (chunk == chunk_one || chunk == chunk_last) + { + // Make sure the resulting buffer is not NULL (failed that, this + // parameter will be skipped by the query machinery). + // + if (size_ == 0) + buf_.capacity (1); + + break; + } + else if (chunk == chunk_null) + break; + } + } + } +} diff --git a/libodb-mssql/odb/mssql/query.hxx b/libodb-mssql/odb/mssql/query.hxx new file mode 100644 index 0000000..18db752 --- /dev/null +++ b/libodb-mssql/odb/mssql/query.hxx @@ -0,0 +1,2711 @@ +// file : odb/mssql/query.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_QUERY_HXX +#define ODB_MSSQL_QUERY_HXX + +#include + +#include +#include +#include // std::size_t + +#include // odb::query_column +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace odb +{ + namespace mssql + { + // For precision, 0 is invalid so we can use it as a special value + // to indicate that the precision has not been specified. For scale, + // however, 0 is a valid value and for some types (e.g., TIME) if + // the scale is not specified, it defaults to something other than + // 0. As a result, for scale, the not specific special value will + // be 0xFFFF (USHORT_MAX). + // + template + struct val_bind + { + typedef const T& type; + + explicit + val_bind (type v, unsigned short p = 0, unsigned short s = 0xFFFF) + : val (v), prec (p), scale (s) {} + + type val; + + unsigned short prec; + unsigned short scale; + }; + + template + struct val_bind + { + typedef const T* type; + + explicit + val_bind (type v, unsigned short p = 0, unsigned short s = 0xFFFF) + : val (v), prec (p), scale (s) {} + + type val; + + unsigned short prec; + unsigned short scale; + }; + + template + struct ref_bind + { + typedef const T& type; + + explicit + ref_bind (type r, unsigned short p = 0, unsigned short s = 0xFFFF) + : ref (r), prec (p), scale (s) {} + + const void* + ptr () const {return &ref;} + + type ref; + + unsigned short prec; + unsigned short scale; + }; + + template + struct ref_bind + { + typedef const T* type; + + explicit + ref_bind (type r, unsigned short p = 0, unsigned short s = 0xFFFF) + : ref (r), prec (p), scale (s) {} + + // Allow implicit conversion from decayed ref_bind's. + // + ref_bind (ref_bind r): ref (r.ref), prec (r.prec), scale (r.scale) {} + ref_bind (ref_bind r) + : ref (r.ref), prec (r.prec), scale (r.scale) {} + + const void* + ptr () const {return ref;} + + type ref; + + unsigned short prec; + unsigned short scale; + }; + + template + struct val_bind_typed: val_bind + { + explicit + val_bind_typed (typename val_bind::type v, + unsigned short p = 0, + unsigned short s = 0xFFFF): val_bind (v, p, s) {} + }; + + template + struct ref_bind_typed: ref_bind + { + explicit + ref_bind_typed (typename ref_bind::type r, + unsigned short p = 0, + unsigned short s = 0xFFFF): ref_bind (r, p, s) {} + }; + + struct LIBODB_MSSQL_EXPORT query_param: details::shared_base + { + typedef mssql::bind bind_type; + + virtual + ~query_param (); + + bool + reference () const + { + return value_ != 0; + } + + virtual bool + init () = 0; + + virtual void + bind (bind_type*) = 0; + + protected: + query_param (const void* value) + : value_ (value) + { + } + + protected: + const void* value_; + }; + + // + // + template + struct query_column; + + class LIBODB_MSSQL_EXPORT query_base + { + public: + struct clause_part + { + enum kind_type + { + kind_column, + kind_param, + kind_native, + kind_bool + }; + + clause_part (kind_type k): kind (k), bool_part (false) {} + clause_part (kind_type k, const std::string& p) + : kind (k), part (p), bool_part (false) {} + clause_part (bool p): kind (kind_bool), bool_part (p) {} + + kind_type kind; + std::string part; // If kind is param, then part is conversion expr. + bool bool_part; + }; + + query_base () + : binding_ (0, 0) + { + } + + // True or false literal. + // + explicit + query_base (bool v) + : binding_ (0, 0) + { + append (v); + } + + explicit + query_base (const char* native) + : binding_ (0, 0) + { + clause_.push_back (clause_part (clause_part::kind_native, native)); + } + + explicit + query_base (const std::string& native) + : binding_ (0, 0) + { + clause_.push_back (clause_part (clause_part::kind_native, native)); + } + + query_base (const char* table, const char* column) + : binding_ (0, 0) + { + append (table, column); + } + + template + explicit + query_base (val_bind v) + : binding_ (0, 0) + { + *this += v; + } + + template + explicit + query_base (val_bind_typed v) + : binding_ (0, 0) + { + *this += v; + } + + template + explicit + query_base (ref_bind r) + : binding_ (0, 0) + { + *this += r; + } + + template + explicit + query_base (ref_bind_typed r) + : binding_ (0, 0) + { + *this += r; + } + + template + query_base (const query_column&); + + // Translate common query representation to SQL Server native. Defined + // in query-dynamic.cxx + // + query_base (const odb::query_base&); + + // Copy c-tor and assignment. + // + query_base (const query_base&); + + query_base& + operator= (const query_base&); + + public: + std::string + clause () const; + + const char* + clause_prefix () const; + + // Initialize the by-reference parameters from bound variables. + // + void + init_parameters () const; + + binding& + parameters_binding () const; + + public: + bool + empty () const + { + return clause_.empty (); + } + + static const query_base true_expr; + + bool + const_true () const + { + return clause_.size () == 1 && + clause_.front ().kind == clause_part::kind_bool && + clause_.front ().bool_part; + } + + void + optimize (); + + public: + template + static val_bind + _val (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF) + { + return val_bind (x, prec, scale); + } + + template + static val_bind_typed + _val (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF) + { + return val_bind_typed (x, prec, scale); + } + + template + static ref_bind + _ref (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF) + { + return ref_bind (x, prec, scale); + } + + template + static ref_bind_typed + _ref (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF) + { + return ref_bind_typed (x, prec, scale); + } + + // Some compilers (notably VC++), when deducing const T& from const + // array do not strip const from the array type. As a result, in the + // above signatures we get, for example, T = const char[4] instead + // of T = char[4], which is what we want. So to "fix" such compilers, + // we will have to provide the following specializations of the above + // functions. + // + template + static val_bind + _val (const T (&x) [N], unsigned short p = 0, unsigned short s = 0xFFFF) + { + return val_bind (x, p, s); + } + + template + static val_bind_typed + _val (const T (&x) [N], unsigned short p = 0, unsigned short s = 0xFFFF) + { + return val_bind_typed (x, p, s); + } + + template + static ref_bind + _ref (const T (&x) [N], unsigned short p = 0, unsigned short s = 0xFFFF) + { + return ref_bind (x, p, s); + } + + template + static ref_bind_typed + _ref (const T (&x) [N], unsigned short p = 0, unsigned short s = 0xFFFF) + { + return ref_bind_typed (x, p, s); + } + + public: + query_base& + operator+= (const query_base&); + + query_base& + operator+= (const std::string& q) + { + append (q); + return *this; + } + + template + query_base& + operator+= (val_bind v) + { + append::db_type_id> ( + v, details::conversion::to ()); + return *this; + } + + template + query_base& + operator+= (val_bind_typed v) + { + // We are not using default type_traits so no default conversion + // either. + // + append (v, 0); + return *this; + } + + template + query_base& + operator+= (ref_bind r) + { + append::db_type_id> ( + r, details::conversion::to ()); + return *this; + } + + template + query_base& + operator+= (ref_bind_typed r) + { + // We are not using default type_traits so no default conversion + // either. + // + append (r, 0); + return *this; + } + + template + query_base& + operator+= (const query_column&); + + // Implementation details. + // + public: + template + void + append (val_bind, const char* conv); + + template + void + append (ref_bind, const char* conv); + + void + append (details::shared_ptr, const char* conv); + + void + append (bool v) + { + clause_.push_back (clause_part (v)); + } + + void + append (const std::string& native); + + void + append (const char* native) // Clashes with append(bool). + { + append (std::string (native)); + } + + void + append (const char* table, const char* column); + + private: + typedef std::vector clause_type; + typedef std::vector > parameters_type; + + clause_type clause_; + parameters_type parameters_; + mutable std::vector bind_; + mutable binding binding_; + }; + + inline query_base + operator+ (const query_base& x, const query_base& y) + { + query_base r (x); + r += y; + return r; + } + + template + inline query_base + operator+ (const query_base& q, val_bind b) + { + query_base r (q); + r += b; + return r; + } + + template + inline query_base + operator+ (val_bind b, const query_base& q) + { + query_base r; + r += b; + r += q; + return r; + } + + template + inline query_base + operator+ (const query_base& q, val_bind_typed b) + { + query_base r (q); + r += b; + return r; + } + + template + inline query_base + operator+ (val_bind_typed b, const query_base& q) + { + query_base r; + r += b; + r += q; + return r; + } + + template + inline query_base + operator+ (const query_base& q, ref_bind b) + { + query_base r (q); + r += b; + return r; + } + + template + inline query_base + operator+ (ref_bind b, const query_base& q) + { + query_base r; + r += b; + r += q; + return r; + } + + template + inline query_base + operator+ (const query_base& q, ref_bind_typed b) + { + query_base r (q); + r += b; + return r; + } + + template + inline query_base + operator+ (ref_bind_typed b, const query_base& q) + { + query_base r; + r += b; + r += q; + return r; + } + + inline query_base + operator+ (const query_base& q, const std::string& s) + { + query_base r (q); + r += s; + return r; + } + + inline query_base + operator+ (const std::string& s, const query_base& q) + { + query_base r (s); + r += q; + return r; + } + + template + inline query_base + operator+ (const std::string& s, val_bind b) + { + query_base r (s); + r += b; + return r; + } + + template + inline query_base + operator+ (val_bind b, const std::string& s) + { + query_base r; + r += b; + r += s; + return r; + } + + template + inline query_base + operator+ (const std::string& s, val_bind_typed b) + { + query_base r (s); + r += b; + return r; + } + + template + inline query_base + operator+ (val_bind_typed b, const std::string& s) + { + query_base r; + r += b; + r += s; + return r; + } + + template + inline query_base + operator+ (const std::string& s, ref_bind b) + { + query_base r (s); + r += b; + return r; + } + + template + inline query_base + operator+ (ref_bind b, const std::string& s) + { + query_base r; + r += b; + r += s; + return r; + } + + template + inline query_base + operator+ (const std::string& s, ref_bind_typed b) + { + query_base r (s); + r += b; + return r; + } + + template + inline query_base + operator+ (ref_bind_typed b, const std::string& s) + { + query_base r; + r += b; + r += s; + return r; + } + + LIBODB_MSSQL_EXPORT query_base + operator&& (const query_base& x, const query_base& y); + + LIBODB_MSSQL_EXPORT query_base + operator|| (const query_base& x, const query_base& y); + + LIBODB_MSSQL_EXPORT query_base + operator! (const query_base& x); + + // query_column + // + struct LIBODB_MSSQL_EXPORT query_column_base + { + // Note that we keep shallow copies of the table, column, and conversion + // expression. The latter can be NULL. + // + query_column_base (const char* table, + const char* column, + const char* conv, + unsigned short prec, + unsigned short scale) + : table_ (table), column_ (column), conversion_ (conv), + prec_ (prec), scale_ (scale) + { + } + + const char* + table () const + { + return table_; + } + + const char* + column () const + { + return column_; + } + + // Can be NULL. + // + const char* + conversion () const + { + return conversion_; + } + + unsigned short + prec () const + { + return prec_; + } + + unsigned short + scale () const + { + return scale_; + } + + protected: + const char* table_; + const char* column_; + const char* conversion_; + + unsigned short prec_; + unsigned short scale_; + }; + + template + struct query_column: query_column_base + { + typedef typename decay_traits::type decayed_type; + + // Note that we keep shalow copies of the table, column, and conversion + // expression. The latter can be NULL. + // + query_column (const char* table, + const char* column, + const char* conv, + unsigned short prec = 0, + unsigned short scale = 0xFFFF) + : query_column_base (table, column, conv, prec, scale) {} + + // Implementation is in query-dynamic.ixx. + // + query_column (odb::query_column&, + const char* table, + const char* column, + const char* conv, + unsigned short prec = 0, + unsigned short scale = 0xFFFF); + + // is_null, is_not_null + // + public: + query_base + is_null () const + { + query_base q (table_, column_); + q += "IS NULL"; + return q; + } + + query_base + is_not_null () const + { + query_base q (table_, column_); + q += "IS NOT NULL"; + return q; + } + + // in + // + public: + query_base + in (decayed_type, decayed_type) const; + + query_base + in (decayed_type, decayed_type, decayed_type) const; + + query_base + in (decayed_type, decayed_type, decayed_type, decayed_type) const; + + query_base + in (decayed_type, decayed_type, decayed_type, decayed_type, + decayed_type) const; + + template + query_base + in_range (I begin, I end) const; + + // like + // + public: + query_base + like (decayed_type pattern) const + { + return like (val_bind (pattern)); + } + + query_base + like (val_bind pattern) const; + + template + query_base + like (val_bind pattern) const + { + return like (val_bind (decayed_type (pattern.val))); + } + + query_base + like (ref_bind pattern) const; + + query_base + like (decayed_type pattern, decayed_type escape) const + { + return like (val_bind (pattern), escape); + } + + query_base + like (val_bind pattern, decayed_type escape) const; + + template + query_base + like (val_bind pattern, decayed_type escape) const + { + return like (val_bind (decayed_type (pattern.val)), escape); + } + + query_base + like (ref_bind pattern, decayed_type escape) const; + + // = + // + public: + query_base + equal (decayed_type v) const + { + return equal (val_bind (v)); + } + + query_base + equal (val_bind v) const + { + v.prec = prec_; + v.scale = scale_; + + query_base q (table_, column_); + q += "="; + q.append (v, conversion_); + return q; + } + + template + query_base + equal (val_bind v) const + { + return equal (val_bind (decayed_type (v.val)));; + } + + query_base + equal (ref_bind r) const + { + r.prec = prec_; + r.scale = scale_; + + query_base q (table_, column_); + q += "="; + q.append (r, conversion_); + return q; + } + + friend query_base + operator== (const query_column& c, decayed_type v) + { + return c.equal (v); + } + + friend query_base + operator== (decayed_type v, const query_column& c) + { + return c.equal (v); + } + + friend query_base + operator== (const query_column& c, val_bind v) + { + return c.equal (v); + } + + friend query_base + operator== (val_bind v, const query_column& c) + { + return c.equal (v); + } + + template + friend query_base + operator== (const query_column& c, val_bind v) + { + return c.equal (v); + } + + template + friend query_base + operator== (val_bind v, const query_column& c) + { + return c.equal (v); + } + + friend query_base + operator== (const query_column& c, ref_bind r) + { + return c.equal (r); + } + + friend query_base + operator== (ref_bind r, const query_column& c) + { + return c.equal (r); + } + + // != + // + public: + query_base + unequal (decayed_type v) const + { + return unequal (val_bind (v)); + } + + query_base + unequal (val_bind v) const + { + v.prec = prec_; + v.scale = scale_; + + query_base q (table_, column_); + q += "!="; + q.append (v, conversion_); + return q; + } + + template + query_base + unequal (val_bind v) const + { + return unequal (val_bind (decayed_type (v.val))); + } + + query_base + unequal (ref_bind r) const + { + r.prec = prec_; + r.scale = scale_; + + query_base q (table_, column_); + q += "!="; + q.append (r, conversion_); + return q; + } + + friend query_base + operator!= (const query_column& c, decayed_type v) + { + return c.unequal (v); + } + + friend query_base + operator!= (decayed_type v, const query_column& c) + { + return c.unequal (v); + } + + friend query_base + operator!= (const query_column& c, val_bind v) + { + return c.unequal (v); + } + + friend query_base + operator!= (val_bind v, const query_column& c) + { + return c.unequal (v); + } + + template + friend query_base + operator!= (const query_column& c, val_bind v) + { + return c.unequal (v); + } + + template + friend query_base + operator!= (val_bind v, const query_column& c) + { + return c.unequal (v); + } + + friend query_base + operator!= (const query_column& c, ref_bind r) + { + return c.unequal (r); + } + + friend query_base + operator!= (ref_bind r, const query_column& c) + { + return c.unequal (r); + } + + // < + // + public: + query_base + less (decayed_type v) const + { + return less (val_bind (v)); + } + + query_base + less (val_bind v) const + { + v.prec = prec_; + v.scale = scale_; + + query_base q (table_, column_); + q += "<"; + q.append (v, conversion_); + return q; + } + + template + query_base + less (val_bind v) const + { + return less (val_bind (decayed_type (v.val))); + } + + query_base + less (ref_bind r) const + { + r.prec = prec_; + r.scale = scale_; + + query_base q (table_, column_); + q += "<"; + q.append (r, conversion_); + return q; + } + + friend query_base + operator< (const query_column& c, decayed_type v) + { + return c.less (v); + } + + friend query_base + operator< (decayed_type v, const query_column& c) + { + return c.greater (v); + } + + friend query_base + operator< (const query_column& c, val_bind v) + { + return c.less (v); + } + + friend query_base + operator< (val_bind v, const query_column& c) + { + return c.greater (v); + } + + template + friend query_base + operator< (const query_column& c, val_bind v) + { + return c.less (v); + } + + template + friend query_base + operator< (val_bind v, const query_column& c) + { + return c.greater (v); + } + + friend query_base + operator< (const query_column& c, ref_bind r) + { + return c.less (r); + } + + friend query_base + operator< (ref_bind r, const query_column& c) + { + return c.greater (r); + } + + // > + // + public: + query_base + greater (decayed_type v) const + { + return greater (val_bind (v)); + } + + query_base + greater (val_bind v) const + { + v.prec = prec_; + v.scale = scale_; + + query_base q (table_, column_); + q += ">"; + q.append (v, conversion_); + return q; + } + + template + query_base + greater (val_bind v) const + { + return greater (val_bind (decayed_type (v.val))); + } + + query_base + greater (ref_bind r) const + { + r.prec = prec_; + r.scale = scale_; + + query_base q (table_, column_); + q += ">"; + q.append (r, conversion_); + return q; + } + + friend query_base + operator> (const query_column& c, decayed_type v) + { + return c.greater (v); + } + + friend query_base + operator> (decayed_type v, const query_column& c) + { + return c.less (v); + } + + friend query_base + operator> (const query_column& c, val_bind v) + { + return c.greater (v); + } + + friend query_base + operator> (val_bind v, const query_column& c) + { + return c.less (v); + } + + template + friend query_base + operator> (const query_column& c, val_bind v) + { + return c.greater (v); + } + + template + friend query_base + operator> (val_bind v, const query_column& c) + { + return c.less (v); + } + + friend query_base + operator> (const query_column& c, ref_bind r) + { + return c.greater (r); + } + + friend query_base + operator> (ref_bind r, const query_column& c) + { + return c.less (r); + } + + // <= + // + public: + query_base + less_equal (decayed_type v) const + { + return less_equal (val_bind (v)); + } + + query_base + less_equal (val_bind v) const + { + v.prec = prec_; + v.scale = scale_; + + query_base q (table_, column_); + q += "<="; + q.append (v, conversion_); + return q; + } + + template + query_base + less_equal (val_bind v) const + { + return less_equal (val_bind (decayed_type (v.val))); + } + + query_base + less_equal (ref_bind r) const + { + r.prec = prec_; + r.scale = scale_; + + query_base q (table_, column_); + q += "<="; + q.append (r, conversion_); + return q; + } + + friend query_base + operator<= (const query_column& c, decayed_type v) + { + return c.less_equal (v); + } + + friend query_base + operator<= (decayed_type v, const query_column& c) + { + return c.greater_equal (v); + } + + friend query_base + operator<= (const query_column& c, val_bind v) + { + return c.less_equal (v); + } + + friend query_base + operator<= (val_bind v, const query_column& c) + { + return c.greater_equal (v); + } + + template + friend query_base + operator<= (const query_column& c, val_bind v) + { + return c.less_equal (v); + } + + template + friend query_base + operator<= (val_bind v, const query_column& c) + { + return c.greater_equal (v); + } + + friend query_base + operator<= (const query_column& c, ref_bind r) + { + return c.less_equal (r); + } + + friend query_base + operator<= (ref_bind r, const query_column& c) + { + return c.greater_equal (r); + } + + // >= + // + public: + query_base + greater_equal (decayed_type v) const + { + return greater_equal (val_bind (v)); + } + + query_base + greater_equal (val_bind v) const + { + v.prec = prec_; + v.scale = scale_; + + query_base q (table_, column_); + q += ">="; + q.append (v, conversion_); + return q; + } + + template + query_base + greater_equal (val_bind v) const + { + return greater_equal (val_bind (decayed_type (v.val))); + } + + query_base + greater_equal (ref_bind r) const + { + r.prec = prec_; + r.scale = scale_; + + query_base q (table_, column_); + q += ">="; + q.append (r, conversion_); + return q; + } + + friend query_base + operator>= (const query_column& c, decayed_type v) + { + return c.greater_equal (v); + } + + friend query_base + operator>= (decayed_type v, const query_column& c) + { + return c.less_equal (v); + } + + friend query_base + operator>= (const query_column& c, val_bind v) + { + return c.greater_equal (v); + } + + friend query_base + operator>= (val_bind v, const query_column& c) + { + return c.less_equal (v); + } + + template + friend query_base + operator>= (const query_column& c, val_bind v) + { + return c.greater_equal (v); + } + + template + friend query_base + operator>= (val_bind v, const query_column& c) + { + return c.less_equal (v); + } + + friend query_base + operator>= (const query_column& c, ref_bind r) + { + return c.greater_equal (r); + } + + friend query_base + operator>= (ref_bind r, const query_column& c) + { + return c.less_equal (r); + } + + // Column comparison. + // + public: + template + query_base + operator== (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (decay_traits::instance () == + decay_traits::instance ())); + + query_base q (table_, column_); + q += "="; + q.append (c.table (), c.column ()); + return q; + } + + template + query_base + operator!= (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (decay_traits::instance () != + decay_traits::instance ())); + + query_base q (table_, column_); + q += "!="; + q.append (c.table (), c.column ()); + return q; + } + + template + query_base + operator< (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (decay_traits::instance () < + decay_traits::instance ())); + + query_base q (table_, column_); + q += "<"; + q.append (c.table (), c.column ()); + return q; + } + + template + query_base + operator> (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (decay_traits::instance () > + decay_traits::instance ())); + + query_base q (table_, column_); + q += ">"; + q.append (c.table (), c.column ()); + return q; + } + + template + query_base + operator<= (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (decay_traits::instance () <= + decay_traits::instance ())); + + query_base q (table_, column_); + q += "<="; + q.append (c.table (), c.column ()); + return q; + } + + template + query_base + operator>= (const query_column& c) const + { + // We can compare columns only if we can compare their C++ types. + // + (void) (sizeof (decay_traits::instance () >= + decay_traits::instance ())); + + query_base q (table_, column_); + q += ">="; + q.append (c.table (), c.column ()); + return q; + } + }; + + // Provide operator+() for using columns to construct native + // query fragments (e.g., ORDER BY). + // + template + inline query_base + operator+ (const query_column& c, const std::string& s) + { + query_base q (c.table (), c.column ()); + q += s; + return q; + } + + template + inline query_base + operator+ (const std::string& s, const query_column& c) + { + query_base q (s); + q.append (c.table (), c.column ()); + return q; + } + + template + inline query_base + operator+ (const query_column& c, const query_base& q) + { + query_base r (c.table (), c.column ()); + r += q; + return r; + } + + template + inline query_base + operator+ (const query_base& q, const query_column& c) + { + query_base r (q); + r.append (c.table (), c.column ()); + return r; + } + + template + inline query_base& query_base:: + operator+= (const query_column& c) + { + append (c.table (), c.column ()); + return *this; + } + + // + // + template + struct query_param_impl; + + // id_bit. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::bit; + b->buffer = &image_; + b->size_ind = &size_ind_; + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 0; + } + + private: + unsigned char image_; + SQLLEN size_ind_; + }; + + // id_tinyint. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::tinyint; + b->buffer = &image_; + b->size_ind = &size_ind_; + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 0; + } + + private: + unsigned char image_; + SQLLEN size_ind_; + }; + + // id_smallint. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::smallint; + b->buffer = &image_; + b->size_ind = &size_ind_; + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 0; + } + + private: + short image_; + SQLLEN size_ind_; + }; + + // id_int. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::int_; + b->buffer = &image_; + b->size_ind = &size_ind_; + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 0; + } + + private: + int image_; + SQLLEN size_ind_; + }; + + // id_bigint. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::bigint; + b->buffer = &image_; + b->size_ind = &size_ind_; + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 0; + } + + private: + long long image_; + SQLLEN size_ind_; + }; + + // id_decimal. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), + prec_ (r.prec != 0 ? r.prec : 18), // Default is 18. + scale_ (r.scale != 0xFFFF ? r.scale : 0) // Default is 0. + { + } + + query_param_impl (val_bind v) + : query_param (0), + prec_ (v.prec != 0 ? v.prec : 18), // Default is 18. + scale_ (v.scale) + { + init (v.val); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::decimal; + b->buffer = &image_; + b->size_ind = &size_ind_; + // Encode precision (p) and scale (s) as (p * 100 + s). + // + b->capacity = static_cast (prec_ * 100 + scale_); + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 0; + } + + private: + unsigned short prec_; + unsigned short scale_; + + decimal image_; + SQLLEN size_ind_; + }; + + // id_smallmoney. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::smallmoney; + b->buffer = &image_; + b->size_ind = &size_ind_; + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 4; + } + + private: + smallmoney image_; + SQLLEN size_ind_; + }; + + // id_money. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::money; + b->buffer = &image_; + b->size_ind = &size_ind_; + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 8; + } + + private: + money image_; + SQLLEN size_ind_; + }; + + // id_float4. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), + prec_ (r.prec != 0 ? r.prec : 24) + { + } + + query_param_impl (val_bind v) + : query_param (0), + prec_ (v.prec != 0 ? v.prec : 24) + { + init (v.val); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::float4; + b->buffer = &image_; + b->size_ind = &size_ind_; + b->capacity = static_cast (prec_); + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 0; + } + + private: + unsigned short prec_; + float image_; + SQLLEN size_ind_; + }; + + // id_float8. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), + prec_ (r.prec != 0 ? r.prec : 53) + { + } + + query_param_impl (val_bind v) + : query_param (0), + prec_ (v.prec != 0 ? v.prec : 53) + { + init (v.val); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::float8; + b->buffer = &image_; + b->size_ind = &size_ind_; + b->capacity = static_cast (prec_); + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 0; + } + + private: + unsigned short prec_; + double image_; + SQLLEN size_ind_; + }; + + // id_string. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), + // Default to short data max (1024). + buf_ (r.prec != 0 ? r.prec : 1024) + { + } + + query_param_impl (val_bind v) + : query_param (0), + // Default to short data max (1024). + buf_ (v.prec != 0 ? v.prec : 1024) + { + init (v.val); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::string; + b->buffer = buf_.data (); + b->size_ind = &size_ind_; + // Extra byte for the null terminator (convention). + // + b->capacity = static_cast (buf_.capacity () + 1); + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + std::size_t size (0); + value_traits::set_image ( + buf_.data (), buf_.capacity (), size, is_null, v); + size_ind_ = static_cast (size); + } + + private: + details::buffer buf_; + SQLLEN size_ind_; + }; + + // id_nstring. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), + // Precision is in 2-byte chars. Default to short data max (1024). + buf_ (r.prec != 0 ? r.prec * 2 : 1024) + { + } + + query_param_impl (val_bind v) + : query_param (0), + // Precision is in 2-byte chars. Default to short data max (1024). + buf_ (v.prec != 0 ? v.prec * 2 : 1024) + { + init (v.val); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::nstring; + b->buffer = buf_.data (); + b->size_ind = &size_ind_; + // Extra two bytes for the null terminator (convention). + // + b->capacity = static_cast (buf_.capacity () + 2); + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + std::size_t size (0); + value_traits::set_image ( + reinterpret_cast (buf_.data ()), + buf_.capacity () / 2, + size, + is_null, + v); + size_ind_ = static_cast (size * 2); + } + + private: + details::buffer buf_; + SQLLEN size_ind_; + }; + + // id_binary. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), + // Default to short data max (1024). + buf_ (r.prec != 0 ? r.prec : 1024) + { + } + + query_param_impl (val_bind v) + : query_param (0), + // Default to short data max (1024). + buf_ (v.prec != 0 ? v.prec : 1024) + { + init (v.val); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::binary; + b->buffer = buf_.data (); + b->size_ind = &size_ind_; + b->capacity = static_cast (buf_.capacity ()); + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + std::size_t size (0); + value_traits::set_image ( + buf_.data (), buf_.capacity (), size, is_null, v); + size_ind_ = static_cast (size); + } + + private: + details::buffer buf_; + SQLLEN size_ind_; + }; + + // long_query_param_impl + // + // For long data we cannot assume that the by-value parameter will + // still be alive when we execute the query (and when the callback + // will be called to provide the data). So we have to make a private + // copy of the data and use that when the time comes. + // + class LIBODB_MSSQL_EXPORT long_query_param_impl + { + protected: + long_query_param_impl (): buf_ (0) {} + + void + copy (); + + protected: + details::buffer buf_; + std::size_t size_; + long_callback callback_; + }; + + // id_long_string. + // + template + struct query_param_impl: query_param, + long_query_param_impl + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), prec_ (r.prec) + { + } + + query_param_impl (val_bind v) + : query_param (0), prec_ (v.prec) + { + init (v.val); + copy (); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + // If this is a by-value parameter then we already have the + // buffer containing all the data. So instead of using the + // callback mechanism, bind the buffer directly using the + // short data approach. SQLLEN (int on 32-bit platforms) + // can represent maximum size of 2^31 bytes which happens + // to be greater than the maximum size of VARCHAR(max) or + // TEXT (both 2^31-1 bytes). + // + if (reference ()) + { + b->type = bind::long_string; + b->buffer = &this->long_query_param_impl::callback_; + b->size_ind = &size_ind_; + b->capacity = static_cast (prec_); + size_ind_ = SQL_DATA_AT_EXEC; + } + else + { + b->type = bind::string; + b->buffer = buf_.data (); + b->size_ind = &size_ind_; + // Extra byte for the null terminator (convention). + // + b->capacity = static_cast (prec_ != 0 ? prec_ + 1 : 0); + size_ind_ = static_cast (size_); + } + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image ( + long_query_param_impl::callback_.callback.param, + long_query_param_impl::callback_.context.param, + is_null, + v); + } + + private: + unsigned short prec_; + SQLLEN size_ind_; + }; + + // id_long_nstring. + // + template + struct query_param_impl: query_param, + long_query_param_impl + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), prec_ (r.prec) + { + } + + query_param_impl (val_bind v) + : query_param (0), prec_ (v.prec) + { + init (v.val); + copy (); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + // If this is a by-value parameter then we already have the + // buffer containing all the data. So instead of using the + // callback mechanism, bind the buffer directly using the + // short data approach. SQLLEN (int on 32-bit platforms) + // can represent maximum size of 2^31 bytes which happens + // to be greater than the maximum size of NVARCHAR(max) or + // NTEXT (both 2^31-1 bytes). + // + if (reference ()) + { + b->type = bind::long_nstring; + b->buffer = &this->long_query_param_impl::callback_; + b->size_ind = &size_ind_; + b->capacity = static_cast (prec_ * 2); // In bytes. + size_ind_ = SQL_DATA_AT_EXEC; + } + else + { + b->type = bind::nstring; + b->buffer = buf_.data (); + b->size_ind = &size_ind_; + // In bytes, extra character for the null terminator (convention). + // + b->capacity = static_cast (prec_ != 0 ? (prec_ + 1) * 2 : 0); + size_ind_ = static_cast (size_); + } + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image ( + long_query_param_impl::callback_.callback.param, + long_query_param_impl::callback_.context.param, + is_null, + v); + } + + private: + unsigned short prec_; + SQLLEN size_ind_; + }; + + // id_long_binary. + // + template + struct query_param_impl: query_param, + long_query_param_impl + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), prec_ (r.prec) + { + } + + query_param_impl (val_bind v) + : query_param (0), prec_ (v.prec) + { + init (v.val); + copy (); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + // If this is a by-value parameter then we already have the + // buffer containing all the data. So instead of using the + // callback mechanism, bind the buffer directly using the + // short data approach. SQLLEN (int on 32-bit platforms) + // can represent maximum size of 2^31 bytes which happens + // to be greater than the maximum size of VARBINARY(max) + // or IMAGE (both 2^31-1 bytes). + // + if (reference ()) + { + b->type = bind::long_binary; + b->buffer = &this->long_query_param_impl::callback_; + b->size_ind = &size_ind_; + size_ind_ = SQL_DATA_AT_EXEC; + } + else + { + b->type = bind::binary; + b->buffer = buf_.data (); + b->size_ind = &size_ind_; + size_ind_ = static_cast (size_); + } + + b->capacity = static_cast (prec_); + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image ( + long_query_param_impl::callback_.callback.param, + long_query_param_impl::callback_.context.param, + is_null, + v); + } + + private: + unsigned short prec_; + SQLLEN size_ind_; + }; + + // id_date. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::date; + b->buffer = &image_; + b->size_ind = &size_ind_; + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 0; + } + + private: + date image_; + SQLLEN size_ind_; + }; + + // id_time. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), + scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default is 7. + { + } + + query_param_impl (val_bind v) + : query_param (0), + scale_ (v.scale != 0xFFFF ? v.scale : 7) // Default is 7. + { + init (v.val); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::time; + b->buffer = &image_; + b->size_ind = &size_ind_; + b->capacity = static_cast (scale_); + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, scale_, is_null, v); + size_ind_ = static_cast (sizeof (image_)); + } + + private: + unsigned short scale_; + time image_; + SQLLEN size_ind_; + }; + + // id_datetime. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), + scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default to datetime2/7. + { + } + + query_param_impl (val_bind v) + : query_param (0), + scale_ (v.scale != 0xFFFF ? v.scale : 7) // Default to datetime2/7. + { + init (v.val); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::datetime; + b->buffer = &image_; + b->size_ind = &size_ind_; + b->capacity = static_cast (scale_); + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, scale_, is_null, v); + size_ind_ = 0; + } + + private: + unsigned short scale_; + datetime image_; + SQLLEN size_ind_; + }; + + // id_datetimeoffset. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) + : query_param (r.ptr ()), + scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default is 7. + { + } + + query_param_impl (val_bind v) + : query_param (0), + scale_ (v.scale != 0xFFFF ? v.scale : 7) // Default is 7. + { + init (v.val); + } + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::datetimeoffset; + b->buffer = &image_; + b->size_ind = &size_ind_; + b->capacity = static_cast (scale_); + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image ( + image_, scale_, is_null, v); + size_ind_ = static_cast (sizeof (image_)); + } + + private: + unsigned short scale_; + datetimeoffset image_; + SQLLEN size_ind_; + }; + + // id_uniqueidentifier. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::uniqueidentifier; + b->buffer = &image_; + b->size_ind = &size_ind_; + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 0; + } + + private: + uniqueidentifier image_; + SQLLEN size_ind_; + }; + + // id_rowversion. + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (r.ptr ()) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual bool + init () + { + init (*static_cast (value_)); + return false; + } + + virtual void + bind (bind_type* b) + { + b->type = bind::rowversion; + b->buffer = &image_; + b->size_ind = &size_ind_; + } + + private: + void + init (typename decay_traits::type v) + { + bool is_null (false); // Can't be NULL. + value_traits::set_image (image_, is_null, v); + size_ind_ = 8; + } + + private: + unsigned char image_[8]; + SQLLEN size_ind_; + }; + } +} + +// odb::mssql::query and odb::query specialization for SQL Server. +// +namespace odb +{ + namespace mssql + { + template + class query: public query_base, + public query_selector::columns_type + { + public: + // We don't define any typedefs here since they may clash with + // column names defined by our base type. + // + + query () + { + } + + explicit + query (bool v) + : query_base (v) + { + } + + explicit + query (const char* q) + : query_base (q) + { + } + + explicit + query (const std::string& q) + : query_base (q) + { + } + + template + explicit + query (val_bind v) + : query_base (v) + { + } + + template + explicit + query (ref_bind r) + : query_base (r) + { + } + + query (const query_base& q) + : query_base (q) + { + } + + template + query (const query_column& qc) + : query_base (qc) + { + } + + query (const odb::query_base& q) + : query_base (q) + { + } + }; + + namespace core + { + using mssql::query; + } + } + + // Derive odb::query from odb::mssql::query so that it can be + // implicitly converted in mssql::database::query() calls. + // + template + class query: public mssql::query + { + public: + // We don't define any typedefs here since they may clash with + // column names defined by our base type. + // + + query () + { + } + + explicit + query (bool v) + : mssql::query (v) + { + } + + explicit + query (const char* q) + : mssql::query (q) + { + } + + explicit + query (const std::string& q) + : mssql::query (q) + { + } + + template + explicit + query (mssql::val_bind v) + : mssql::query (v) + { + } + + template + explicit + query (mssql::ref_bind r) + : mssql::query (r) + { + } + + query (const mssql::query_base& q) + : mssql::query (q) + { + } + + template + query (const mssql::query_column& qc) + : mssql::query (qc) + { + } + }; +} + +#include +#include + +#include + +#endif // ODB_MSSQL_QUERY_HXX diff --git a/libodb-mssql/odb/mssql/query.ixx b/libodb-mssql/odb/mssql/query.ixx new file mode 100644 index 0000000..0467667 --- /dev/null +++ b/libodb-mssql/odb/mssql/query.ixx @@ -0,0 +1,34 @@ +// file : odb/mssql/query.ixx +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace mssql + { + inline binding& query_base:: + parameters_binding () const + { + return binding_; + } + + template + inline void query_base:: + append (val_bind v, const char* conv) + { + append ( + details::shared_ptr ( + new (details::shared) query_param_impl (v)), + conv); + } + + template + inline void query_base:: + append (ref_bind r, const char* conv) + { + append ( + details::shared_ptr ( + new (details::shared) query_param_impl (r)), + conv); + } + } +} diff --git a/libodb-mssql/odb/mssql/query.txx b/libodb-mssql/odb/mssql/query.txx new file mode 100644 index 0000000..d01747c --- /dev/null +++ b/libodb-mssql/odb/mssql/query.txx @@ -0,0 +1,169 @@ +// file : odb/mssql/query.txx +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace mssql + { + // + // query_base + // + + template + query_base:: + query_base (const query_column& c) + : binding_ (0, 0) + { + // Cannot use IS TRUE here since database type can be a non- + // integral type. + // + append (c.table (), c.column ()); + append ("="); + append (val_bind (true, c.prec (), c.scale ()), + c.conversion ()); + } + + // + // query_column + // + + // in + // + template + query_base query_column:: + in (decayed_type v1, decayed_type v2) const + { + query_base q (table_, column_); + q += "IN ("; + q.append (val_bind (v1, prec_, scale_), conversion_); + q += ","; + q.append (val_bind (v2, prec_, scale_), conversion_); + q += ")"; + return q; + } + + template + query_base query_column:: + in (decayed_type v1, decayed_type v2, decayed_type v3) const + { + query_base q (table_, column_); + q += "IN ("; + q.append (val_bind (v1, prec_, scale_), conversion_); + q += ","; + q.append (val_bind (v2, prec_, scale_), conversion_); + q += ","; + q.append (val_bind (v3, prec_, scale_), conversion_); + q += ")"; + return q; + } + + template + query_base query_column:: + in (decayed_type v1, decayed_type v2, decayed_type v3, + decayed_type v4) const + { + query_base q (table_, column_); + q += "IN ("; + q.append (val_bind (v1, prec_, scale_), conversion_); + q += ","; + q.append (val_bind (v2, prec_, scale_), conversion_); + q += ","; + q.append (val_bind (v3, prec_, scale_), conversion_); + q += ","; + q.append (val_bind (v4, prec_, scale_), conversion_); + q += ")"; + return q; + } + + template + query_base query_column:: + in (decayed_type v1, decayed_type v2, decayed_type v3, decayed_type v4, + decayed_type v5) const + { + query_base q (table_, column_); + q += "IN ("; + q.append (val_bind (v1, prec_, scale_), conversion_); + q += ","; + q.append (val_bind (v2, prec_, scale_), conversion_); + q += ","; + q.append (val_bind (v3, prec_, scale_), conversion_); + q += ","; + q.append (val_bind (v4, prec_, scale_), conversion_); + q += ","; + q.append (val_bind (v5, prec_, scale_), conversion_); + q += ")"; + return q; + } + + template + template + query_base query_column:: + in_range (I begin, I end) const + { + if (begin != end) + { + query_base q (table_, column_); + q += "IN ("; + + for (I i (begin); i != end; ++i) + { + if (i != begin) + q += ","; + + q.append (val_bind (*i, prec_, scale_), conversion_); + } + + q += ")"; + return q; + } + else + return query_base (false); + } + + // like + // + template + query_base query_column:: + like (val_bind p) const + { + query_base q (table_, column_); + q += "LIKE"; + q.append (p, conversion_); + return q; + } + + template + query_base query_column:: + like (ref_bind p) const + { + query_base q (table_, column_); + q += "LIKE"; + q.append (p, conversion_); + return q; + } + + template + query_base query_column:: + like (val_bind p, decayed_type e) const + { + query_base q (table_, column_); + q += "LIKE"; + q.append (p, conversion_); + q += "ESCAPE"; + q.append (val_bind (e), conversion_); + return q; + } + + template + query_base query_column:: + like (ref_bind p, decayed_type e) const + { + query_base q (table_, column_); + q += "LIKE"; + q.append (p, conversion_); + q += "ESCAPE"; + q.append (val_bind (e), conversion_); + return q; + } + } +} diff --git a/libodb-mssql/odb/mssql/section-statements.hxx b/libodb-mssql/odb/mssql/section-statements.hxx new file mode 100644 index 0000000..0f3500d --- /dev/null +++ b/libodb-mssql/odb/mssql/section-statements.hxx @@ -0,0 +1,201 @@ +// file : odb/mssql/section-statements.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_SECTION_STATEMENTS_HXX +#define ODB_MSSQL_SECTION_STATEMENTS_HXX + +#include + +#include // std::size_t + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace odb +{ + namespace mssql + { + class connection; + + // Template argument is the section traits type. + // + template + class section_statements + { + public: + typedef ST traits; + + typedef typename traits::image_type image_type; + typedef typename traits::id_image_type id_image_type; + + typedef mssql::select_statement select_statement_type; + typedef mssql::update_statement update_statement_type; + + typedef mssql::connection connection_type; + + section_statements (connection_type&, + image_type&, id_image_type&, + binding& id, binding& idv); + + connection_type& + connection () {return conn_;} + + const schema_version_migration& + version_migration (const char* name = "") const + { + if (svm_ == 0) + svm_ = &conn_.database ().schema_version_migration (name); + + return *svm_; + } + + image_type& + image () {return image_;} + + id_image_type& + id_image () {return id_image_;} + + const binding& + id_binding () {return id_binding_;} + + // Id and optimistic concurrency version (if any). + // + const binding& + idv_binding () {return idv_binding_;} + + // Select binding. + // + std::size_t + select_image_version () const { return select_image_version_;} + + void + select_image_version (std::size_t v) {select_image_version_ = v;} + + binding& + select_image_binding () {return select_image_binding_;} + + // Update binding. + // + std::size_t + update_image_version () const { return update_image_version_;} + + void + update_image_version (std::size_t v) {update_image_version_ = v;} + + std::size_t + update_id_binding_version () const { return update_id_binding_version_;} + + void + update_id_binding_version (std::size_t v) {update_id_binding_version_ = v;} + + binding& + update_image_binding () {return update_image_binding_;} + + // + // Statements. + // + + select_statement_type& + select_statement () + { + if (select_ == 0) + select_.reset ( + new (details::shared) select_statement_type ( + conn_, + traits::select_statement, + traits::versioned, // Process if versioned. + false, // Don't optimize. + id_binding_, + select_image_binding_, + false)); + + return *select_; + } + + update_statement_type& + update_statement () + { + if (update_ == 0) + update_.reset ( + new (details::shared) update_statement_type ( + conn_, + traits::update_statement, + traits::versioned, // Process if versioned. + update_image_binding_, + (traits::rowversion ? &idv_binding_ : 0), + false)); + + return *update_; + } + + public: + static const std::size_t id_column_count = traits::id_column_count; + static const std::size_t managed_optimistic_load_column_count = + traits::managed_optimistic_load_column_count; + static const std::size_t managed_optimistic_update_column_count = + traits::managed_optimistic_update_column_count; + static const std::size_t select_column_count = traits::load_column_count; + static const std::size_t update_column_count = + traits::update_column_count; + + private: + section_statements (const section_statements&); + section_statements& operator= (const section_statements&); + + protected: + connection_type& conn_; + mutable const schema_version_migration* svm_; + + // These come from object_statements. + // + image_type& image_; + id_image_type& id_image_; + binding& id_binding_; + binding& idv_binding_; + + // Select binding. + // + std::size_t select_image_version_; + + static const std::size_t select_bind_count = + select_column_count != 0 || managed_optimistic_load_column_count != 0 + ? select_column_count + managed_optimistic_load_column_count + : 1; + + binding select_image_binding_; + bind select_image_bind_[select_bind_count]; + + // Update binding. + // + std::size_t update_image_version_; + std::size_t update_id_binding_version_; + + static const std::size_t update_bind_count = + update_column_count != 0 || managed_optimistic_update_column_count != 0 + ? update_column_count + id_column_count + + managed_optimistic_update_column_count + : 1; + + binding update_image_binding_; + bind update_image_bind_[update_bind_count]; + + details::shared_ptr select_; + details::shared_ptr update_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_SECTION_STATEMENTS_HXX diff --git a/libodb-mssql/odb/mssql/section-statements.txx b/libodb-mssql/odb/mssql/section-statements.txx new file mode 100644 index 0000000..7389d82 --- /dev/null +++ b/libodb-mssql/odb/mssql/section-statements.txx @@ -0,0 +1,50 @@ +// file : odb/mssql/section-statements.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::memset + +namespace odb +{ + namespace mssql + { + template + section_statements:: + section_statements (connection_type& conn, + image_type& im, id_image_type& idim, + binding& id, binding& idv) + : conn_ (conn), + svm_ (0), + image_ (im), + id_image_ (idim), + id_binding_ (id), + idv_binding_ (idv), + select_image_binding_ (select_image_bind_, + select_column_count + + managed_optimistic_load_column_count), + update_image_binding_ (update_image_bind_, + update_column_count + id_column_count + + managed_optimistic_update_column_count) + { + select_image_version_ = 0; + update_image_version_ = 0; + update_id_binding_version_ = 0; + + // If we are using optimistic concurrency, then the select statement + // will override the version member in the object image. + // + if (managed_optimistic_load_column_count != 0) + { + // Getting to the root image in polymorphic case is tricky. + // + typedef object_traits_impl object_traits; + + select_image_binding_.change_callback = + root_image::get ( + image_).change_callback (); + } + + std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); + std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); + } + } +} diff --git a/libodb-mssql/odb/mssql/simple-object-result.hxx b/libodb-mssql/odb/mssql/simple-object-result.hxx new file mode 100644 index 0000000..dcf8243 --- /dev/null +++ b/libodb-mssql/odb/mssql/simple-object-result.hxx @@ -0,0 +1,89 @@ +// file : odb/mssql/simple-object-result.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_SIMPLE_OBJECT_RESULT_HXX +#define ODB_MSSQL_SIMPLE_OBJECT_RESULT_HXX + +#include + +#include // std::size_t + +#include +#include + +#include + +#include +#include // query_base +#include +#include + +namespace odb +{ + namespace mssql + { + template + class object_result_impl: public odb::object_result_impl + { + public: + typedef odb::object_result_impl base_type; + + typedef typename base_type::id_type id_type; + typedef typename base_type::object_type object_type; + typedef typename base_type::pointer_type pointer_type; + + typedef object_traits_impl object_traits; + typedef typename base_type::pointer_traits pointer_traits; + + typedef typename object_traits::statements_type statements_type; + + virtual + ~object_result_impl (); + + object_result_impl (const query_base&, + details::shared_ptr, + statements_type&, + const schema_version_migration*); + + virtual void + load (object_type&, bool fetch); + + virtual id_type + load_id (); + + virtual void + next (); + + virtual void + cache (); + + virtual std::size_t + size (); + + virtual void + invalidate (); + + using base_type::current; + + private: + typedef mssql::change_callback change_callback_type; + + static void + change_callback (void* context); + + private: + details::shared_ptr statement_; + statements_type& statements_; + object_traits_calls tc_; + bool can_load_; + bool use_copy_; + typename object_traits::image_type* image_copy_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_SIMPLE_OBJECT_RESULT_HXX diff --git a/libodb-mssql/odb/mssql/simple-object-result.txx b/libodb-mssql/odb/mssql/simple-object-result.txx new file mode 100644 index 0000000..3a0e984 --- /dev/null +++ b/libodb-mssql/odb/mssql/simple-object-result.txx @@ -0,0 +1,186 @@ +// file : odb/mssql/simple-object-result.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +#include +#include // result_not_cached + +#include // long_data_reload +#include + +namespace odb +{ + namespace mssql + { + template + object_result_impl:: + ~object_result_impl () + { + invalidate (); + } + + template + void object_result_impl:: + invalidate () + { + change_callback_type& cc (statements_.image ().change_callback_); + + if (cc.context == this) + { + cc.callback = 0; + cc.context = 0; + } + + delete image_copy_; + image_copy_ = 0; + + if (!this->end_) + { + statement_->free_result (); + this->end_ = true; + } + + statement_.reset (); + } + + template + object_result_impl:: + object_result_impl (const query_base&, + details::shared_ptr statement, + statements_type& statements, + const schema_version_migration* svm) + : base_type (statements.connection ()), + statement_ (statement), + statements_ (statements), + tc_ (svm), + use_copy_ (false), + image_copy_ (0) + { + } + + template + void object_result_impl:: + load (object_type& obj, bool) + { + if (!can_load_) + throw long_data_reload (); + + // This is a top-level call so the statements cannot be locked. + // + assert (!statements_.locked ()); + typename statements_type::auto_lock l (statements_); + + object_traits::callback (this->db_, obj, callback_event::pre_load); + + typename object_traits::image_type& i ( + use_copy_ ? *image_copy_ : statements_.image ()); + + tc_.init (obj, i, &this->db_); + + // If we are using a copy, make sure the callback information for + // long data also comes from the copy. + // + can_load_ = !statement_->stream_result ( + use_copy_ ? &statements_.image () : 0, + use_copy_ ? image_copy_ : 0); + + // Initialize the id image and binding and load the rest of the object + // (containers, etc). + // + typename object_traits::id_image_type& idi (statements_.id_image ()); + object_traits::init (idi, object_traits::id (i)); + + binding& idb (statements_.id_image_binding ()); + if (idi.version != statements_.id_image_version () || idb.version == 0) + { + object_traits::bind (idb.bind, idi); + statements_.id_image_version (idi.version); + idb.version++; + } + + tc_.load_ (statements_, obj, false); + statements_.load_delayed (tc_.version ()); + l.unlock (); + object_traits::callback (this->db_, obj, callback_event::post_load); + } + + template + typename object_result_impl::id_type + object_result_impl:: + load_id () + { + return object_traits::id ( + use_copy_ ? *image_copy_ : statements_.image ()); + } + + template + void object_result_impl:: + next () + { + can_load_ = true; + this->current (pointer_type ()); + + typename object_traits::image_type& im (statements_.image ()); + change_callback_type& cc (im.change_callback_); + + if (cc.context == this) + { + cc.callback = 0; + cc.context = 0; + } + + use_copy_ = false; + + if (im.version != statements_.select_image_version ()) + { + binding& b (statements_.select_image_binding ()); + tc_.bind (b.bind, im, statement_select); + statements_.select_image_version (im.version); + b.version++; + } + + if (statement_->fetch () == select_statement::no_data) + { + statement_->free_result (); + this->end_ = true; + } + else + { + cc.callback = &change_callback; + cc.context = this; + } + } + + template + void object_result_impl:: + cache () + { + } + + template + std::size_t object_result_impl:: + size () + { + throw result_not_cached (); + } + + template + void object_result_impl:: + change_callback (void* c) + { + object_result_impl* r (static_cast*> (c)); + typename object_traits::image_type& im (r->statements_.image ()); + + if (r->image_copy_ == 0) + r->image_copy_ = new typename object_traits::image_type (im); + else + *r->image_copy_ = im; + + im.change_callback_.callback = 0; + im.change_callback_.context = 0; + + r->use_copy_ = true; + } + } +} diff --git a/libodb-mssql/odb/mssql/simple-object-statements.cxx b/libodb-mssql/odb/mssql/simple-object-statements.cxx new file mode 100644 index 0000000..5d7e8b6 --- /dev/null +++ b/libodb-mssql/odb/mssql/simple-object-statements.cxx @@ -0,0 +1,15 @@ +// file : odb/mssql/simple-object-statements.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +namespace odb +{ + namespace mssql + { + object_statements_base:: + ~object_statements_base () + { + } + } +} diff --git a/libodb-mssql/odb/mssql/simple-object-statements.hxx b/libodb-mssql/odb/mssql/simple-object-statements.hxx new file mode 100644 index 0000000..9cece2c --- /dev/null +++ b/libodb-mssql/odb/mssql/simple-object-statements.hxx @@ -0,0 +1,606 @@ +// file : odb/mssql/simple-object-statements.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_SIMPLE_OBJECT_STATEMENTS_HXX +#define ODB_MSSQL_SIMPLE_OBJECT_STATEMENTS_HXX + +#include + +#include +#include +#include // std::size_t + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + // The extra_statement_cache class is only defined (and used) in + // the generated source file. However, object_statements may be + // referenced from another source file in the case of a polymorphic + // hierarchy (though in this case the extra statement cache is + // not used). As a result, we cannot have a by-value member and + // instead will store a pointer and lazily allocate the cache if + // and when needed. We will also need to store a pointer to the + // deleter function which will be initialized during allocation + // (at that point we know that the cache class is defined). + // + template + struct extra_statement_cache_ptr + { + typedef I image_type; + typedef ID id_image_type; + typedef mssql::connection connection_type; + + extra_statement_cache_ptr (): p_ (0) {} + ~extra_statement_cache_ptr () + { + if (p_ != 0) + (this->*deleter_) (0, 0, 0, 0, 0); + } + + T& + get (connection_type& c, + image_type& im, id_image_type& idim, + binding& id, binding* idv) + { + if (p_ == 0) + allocate (&c, &im, &idim, &id, (idv != 0 ? idv : &id)); + + return *p_; + } + + private: + void + allocate (connection_type*, + image_type*, id_image_type*, + binding*, binding*); + + private: + T* p_; + void (extra_statement_cache_ptr::*deleter_) ( + connection_type*, image_type*, id_image_type*, binding*, binding*); + }; + + template + void extra_statement_cache_ptr:: + allocate (connection_type* c, + image_type* im, id_image_type* idim, + binding* id, binding* idv) + { + // To reduce object code size, this function acts as both allocator + // and deleter. + // + if (p_ == 0) + { + p_ = new T (*c, *im, *idim, *id, *idv); + deleter_ = &extra_statement_cache_ptr::allocate; + } + else + delete p_; + } + + // + // Implementation for objects with object id. + // + + class LIBODB_MSSQL_EXPORT object_statements_base: public statements_base + { + // Locking. + // + public: + void + lock () + { + assert (!locked_); + locked_ = true; + } + + void + unlock () + { + assert (locked_); + locked_ = false; + } + + bool + locked () const + { + return locked_; + } + + struct auto_unlock + { + // Unlocks the statement on construction and re-locks it on + // destruction. + // + auto_unlock (object_statements_base&); + ~auto_unlock (); + + private: + auto_unlock (const auto_unlock&); + auto_unlock& operator= (const auto_unlock&); + + private: + object_statements_base& s_; + }; + + public: + virtual + ~object_statements_base (); + + protected: + object_statements_base (connection_type& conn) + : statements_base (conn), locked_ (false) + { + } + + protected: + bool locked_; + }; + + template + struct optimistic_data; + + template + struct optimistic_data + { + typedef T object_type; + typedef object_traits_impl object_traits; + + optimistic_data (bind*, std::size_t skip, SQLUSMALLINT* status); + + binding* + id_image_binding () {return &id_image_binding_;} + + // The id + optimistic column binding. + // + binding id_image_binding_; + + details::shared_ptr erase_; + }; + + template + struct optimistic_data + { + optimistic_data (bind*, std::size_t, SQLUSMALLINT*) {} + + binding* + id_image_binding () {return 0;} + }; + + template + class object_statements: public object_statements_base + { + public: + typedef T object_type; + typedef object_traits_impl object_traits; + typedef typename object_traits::id_type id_type; + typedef typename object_traits::pointer_type pointer_type; + typedef typename object_traits::image_type image_type; + typedef typename object_traits::id_image_type id_image_type; + + typedef + typename object_traits::pointer_cache_traits + pointer_cache_traits; + + typedef + typename object_traits::extra_statement_cache_type + extra_statement_cache_type; + + typedef mssql::insert_statement insert_statement_type; + typedef mssql::select_statement select_statement_type; + typedef mssql::update_statement update_statement_type; + typedef mssql::delete_statement delete_statement_type; + + // Automatic lock. + // + struct auto_lock + { + // Lock the statements unless they are already locked in which + // case subsequent calls to locked() will return false. + // + auto_lock (object_statements&); + + // Unlock the statements if we are holding the lock and clear + // the delayed loads. This should only happen in case an + // exception is thrown. In normal circumstances, the user + // should call unlock() explicitly. + // + ~auto_lock (); + + // Return true if this auto_lock instance holds the lock. + // + bool + locked () const; + + // Unlock the statements. + // + void + unlock (); + + private: + auto_lock (const auto_lock&); + auto_lock& operator= (const auto_lock&); + + private: + object_statements& s_; + bool locked_; + }; + + public: + object_statements (connection_type&); + + virtual + ~object_statements (); + + // Delayed loading. + // + typedef void (*loader_function) (odb::database&, + const id_type&, + object_type&, + const schema_version_migration*); + + void + delay_load (const id_type& id, + object_type& obj, + const typename pointer_cache_traits::position_type& p, + loader_function l = 0) + { + delayed_.push_back (delayed_load (id, obj, p, l)); + } + + void + load_delayed (const schema_version_migration* svm) + { + assert (locked ()); + + if (!delayed_.empty ()) + load_delayed_ (svm); + } + + void + clear_delayed () + { + if (!delayed_.empty ()) + clear_delayed_ (); + } + + // Object image. + // + image_type& + image (std::size_t i = 0) + { + return images_[i].obj; + } + + // Insert binding. + // + std::size_t + insert_image_version () const { return insert_image_version_;} + + void + insert_image_version (std::size_t v) {insert_image_version_ = v;} + + binding& + insert_image_binding () {return insert_image_binding_;} + + // Update binding. + // + std::size_t + update_image_version () const { return update_image_version_;} + + void + update_image_version (std::size_t v) {update_image_version_ = v;} + + std::size_t + update_id_image_version () const { return update_id_image_version_;} + + void + update_id_image_version (std::size_t v) {update_id_image_version_ = v;} + + binding& + update_image_binding () {return update_image_binding_;} + + // Select binding. + // + std::size_t + select_image_version () const { return select_image_version_;} + + void + select_image_version (std::size_t v) {select_image_version_ = v;} + + binding& + select_image_binding () {return select_image_binding_;} + + // Object id image and binding. + // + id_image_type& + id_image (std::size_t i = 0) {return images_[i].id;} + + std::size_t + id_image_version () const {return id_image_version_;} + + void + id_image_version (std::size_t v) {id_image_version_ = v;} + + binding& + id_image_binding () {return id_image_binding_;} + + // Optimistic id + managed column image binding. It points to + // the same suffix as id binding and they are always updated + // at the same time. + // + binding& + optimistic_id_image_binding () {return *od_.id_image_binding ();} + + // Statements. + // + insert_statement_type& + persist_statement () + { + if (persist_ == 0) + persist_.reset ( + new (details::shared) insert_statement_type ( + conn_, + object_traits::persist_statement, + object_traits::versioned, // Process if versioned. + insert_image_binding_, + object_traits::auto_id, + object_traits::rowversion, + (object_traits::rowversion + ? &optimistic_id_image_binding () + : (object_traits::auto_id ? &id_image_binding () : 0)), + false)); + + return *persist_; + } + + select_statement_type& + find_statement () + { + if (find_ == 0) + find_.reset ( + new (details::shared) select_statement_type ( + conn_, + object_traits::find_statement, + object_traits::versioned, // Process if versioned. + false, // Don't optimize. + id_image_binding_, + select_image_binding_, + false)); + + return *find_; + } + + update_statement_type& + update_statement () + { + if (update_ == 0) + update_.reset ( + new (details::shared) update_statement_type ( + conn_, + object_traits::update_statement, + true, // Unique (0 or 1). + object_traits::versioned, // Process if versioned. + update_image_binding_, + object_traits::rowversion ? &optimistic_id_image_binding () : 0, + false)); + + return *update_; + } + + delete_statement_type& + erase_statement () + { + if (erase_ == 0) + erase_.reset ( + new (details::shared) delete_statement_type ( + conn_, + object_traits::erase_statement, + true, // Unique (0 or 1 affected rows). + id_image_binding_, + false)); + + return *erase_; + } + + delete_statement_type& + optimistic_erase_statement () + { + if (od_.erase_ == 0) + { + od_.erase_.reset ( + new (details::shared) delete_statement_type ( + conn_, + object_traits::optimistic_erase_statement, + true, // Unique (0 or 1 affected rows). + od_.id_image_binding_, + false)); + } + + return *od_.erase_; + } + + // Extra (container, section) statement cache. + // + extra_statement_cache_type& + extra_statement_cache () + { + return extra_statement_cache_.get ( + conn_, + images_[0].obj, images_[0].id, + id_image_binding_, od_.id_image_binding ()); + } + + public: + // select = total - separate_load + // insert = total - inverse - managed_optimistic - auto_id + // update = total - inverse - managed_optimistic - id - readonly + // - separate_update + // + static const std::size_t id_column_count = + object_traits::id_column_count; + + static const std::size_t managed_optimistic_column_count = + object_traits::managed_optimistic_column_count; + + static const std::size_t select_column_count = + object_traits::column_count - + object_traits::separate_load_column_count; + + static const std::size_t insert_column_count = + object_traits::column_count - + object_traits::inverse_column_count - + object_traits::managed_optimistic_column_count - + (object_traits::auto_id ? id_column_count : 0); + + static const std::size_t update_column_count = + insert_column_count - + (object_traits::auto_id ? 0 : id_column_count) - + object_traits::readonly_column_count - + object_traits::separate_update_column_count; + + private: + object_statements (const object_statements&); + object_statements& operator= (const object_statements&); + + protected: + template + void + load_delayed_ (const schema_version_migration*); + + void + clear_delayed_ (); + + protected: + template + friend class polymorphic_derived_object_statements; + + extra_statement_cache_ptr extra_statement_cache_; + + // The UPDATE statement uses both the object and id image. Keep + // them next to each other so that the same skip distance can + // be used in batch binding. + // + struct images + { + image_type obj; + id_image_type id; + }; + + images images_[object_traits::batch]; + SQLUSMALLINT status_[object_traits::batch]; + + // Select binding. + // + std::size_t select_image_version_; + binding select_image_binding_; + bind select_image_bind_[select_column_count]; + + // Insert binding. + // + std::size_t insert_image_version_; + binding insert_image_binding_; + bind insert_image_bind_[ + insert_column_count != 0 ? insert_column_count : 1]; + + // Update binding. Note that the id suffix is bound to id_image_ + // below instead of image_ which makes this binding effectively + // bound to two images. As a result, we have to track versions + // for both of them. If this object uses optimistic concurrency, + // then the binding for the managed column (version, timestamp, + // etc) comes after the id and the image for such a column is + // stored as part of the id image. + // + std::size_t update_image_version_; + std::size_t update_id_image_version_; + binding update_image_binding_; + bind update_image_bind_[update_column_count + id_column_count + + managed_optimistic_column_count]; + + // Id image binding (only used as a parameter or in OUTPUT for + // auto id and version). Uses the suffix in the update bind. + // + std::size_t id_image_version_; + binding id_image_binding_; + + // Extra data for objects with optimistic concurrency support. + // + optimistic_data od_; + + details::shared_ptr persist_; + details::shared_ptr find_; + details::shared_ptr update_; + details::shared_ptr erase_; + + // Delayed loading. + // + struct delayed_load + { + typedef typename pointer_cache_traits::position_type position_type; + + delayed_load () {} + delayed_load (const id_type& i, + object_type& o, + const position_type& p, + loader_function l) + : id (i), obj (&o), pos (p), loader (l) + { + } + + id_type id; + object_type* obj; + position_type pos; + loader_function loader; + }; + + typedef std::vector delayed_loads; + delayed_loads delayed_; + + // Delayed vectors swap guard. See the load_delayed_() function for + // details. + // + struct swap_guard + { + swap_guard (object_statements& os, delayed_loads& dl) + : os_ (os), dl_ (dl) + { + dl_.swap (os_.delayed_); + } + + ~swap_guard () + { + os_.clear_delayed (); + dl_.swap (os_.delayed_); + } + + private: + object_statements& os_; + delayed_loads& dl_; + }; + }; + } +} + +#include +#include + +#include + +#endif // ODB_MSSQL_SIMPLE_OBJECT_STATEMENTS_HXX diff --git a/libodb-mssql/odb/mssql/simple-object-statements.ixx b/libodb-mssql/odb/mssql/simple-object-statements.ixx new file mode 100644 index 0000000..1066850 --- /dev/null +++ b/libodb-mssql/odb/mssql/simple-object-statements.ixx @@ -0,0 +1,68 @@ +// file : odb/mssql/simple-object-statements.ixx +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace mssql + { + // + // auto_unlock + // + inline object_statements_base::auto_unlock:: + auto_unlock (object_statements_base& s) + : s_ (s) + { + s_.unlock (); + } + + inline object_statements_base::auto_unlock:: + ~auto_unlock () + { + s_.lock (); + } + + // + // auto_lock + // + template + inline object_statements::auto_lock:: + auto_lock (object_statements& s) + : s_ (s) + { + if (!s_.locked ()) + { + s_.lock (); + locked_ = true; + } + else + locked_ = false; + } + + template + inline object_statements::auto_lock:: + ~auto_lock () + { + if (locked_) + { + s_.unlock (); + s_.clear_delayed (); + } + } + + template + inline bool object_statements::auto_lock:: + locked () const + { + return locked_; + } + + template + inline void object_statements::auto_lock:: + unlock () + { + assert (locked_); + s_.unlock (); + locked_ = false; + } + } +} diff --git a/libodb-mssql/odb/mssql/simple-object-statements.txx b/libodb-mssql/odb/mssql/simple-object-statements.txx new file mode 100644 index 0000000..06a0651 --- /dev/null +++ b/libodb-mssql/odb/mssql/simple-object-statements.txx @@ -0,0 +1,173 @@ +// file : odb/mssql/simple-object-statements.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::memset + +#include +#include + +#include +#include + +namespace odb +{ + namespace mssql + { + // + // optimistic_data + // + + template + optimistic_data:: + optimistic_data (bind* b, std::size_t skip, SQLUSMALLINT* status) + : id_image_binding_ ( + b, + object_traits::id_column_count + + object_traits::managed_optimistic_column_count, + object_traits::batch, + skip, + status) + { + } + + // + // object_statements + // + + template + object_statements:: + ~object_statements () + { + } + + template + object_statements:: + object_statements (connection_type& conn) + : object_statements_base (conn), + select_image_binding_ (select_image_bind_, select_column_count), + insert_image_binding_ (insert_image_bind_, + insert_column_count, + object_traits::batch, + sizeof (images), + status_), + update_image_binding_ (update_image_bind_, + update_column_count + id_column_count + + managed_optimistic_column_count, + // No support for bulk update and ROWVERSION. + // + (object_traits::rowversion + ? 1 + : object_traits::batch), + sizeof (images), + status_), + id_image_binding_ (update_image_bind_ + update_column_count, + id_column_count, + object_traits::batch, + sizeof (images), + status_), + od_ (update_image_bind_ + update_column_count, + sizeof (images), + status_) + { + // Only versions in the first element used. + // + images_[0].obj.version = 0; + images_[0].id.version = 0; + + select_image_version_ = 0; + insert_image_version_ = 0; + update_image_version_ = 0; + update_id_image_version_ = 0; + id_image_version_ = 0; + + // SELECT statements only use the first element (no batches). + // + select_image_binding_.change_callback = + images_[0].obj.change_callback (); + + std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); + std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); + std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); + } + + template + template + void object_statements:: + load_delayed_ (const schema_version_migration* svm) + { + database& db (connection ().database ()); + + delayed_loads dls; + swap_guard sg (*this, dls); + + while (!dls.empty ()) + { + delayed_load l (dls.back ()); + typename pointer_cache_traits::insert_guard ig (l.pos); + dls.pop_back (); + + if (l.loader == 0) + { + object_traits_calls tc (svm); + + if (!tc.find_ (static_cast (*this), &l.id)) + throw object_not_persistent (); + + // Our find_() version delays result freeing. + // + auto_result ar (*find_); + + object_traits::callback (db, *l.obj, callback_event::pre_load); + + // Our calls to init/load below can result in additional delayed + // loads being added to the delayed_ vector. We need to process + // those before we call the post callback. + // + tc.init (*l.obj, image (), &db); + find_->stream_result (); + ar.free (); + + // Load containers, etc. + // + tc.load_ (static_cast (*this), *l.obj, false); + + if (!delayed_.empty ()) + load_delayed_ (svm); + + // Temporarily unlock the statement for the post_load call so that + // it can load objects of this type recursively. This is safe to do + // because we have completely loaded the current object. Also the + // delayed_ list is clear before the unlock and should be clear on + // re-lock (since a callback can only call public API functions + // which will make sure all the delayed loads are processed before + // returning). + // + { + auto_unlock u (*this); + object_traits::callback (db, *l.obj, callback_event::post_load); + } + } + else + l.loader (db, l.id, *l.obj, svm); + + pointer_cache_traits::load (ig.position ()); + ig.release (); + } + } + + template + void object_statements:: + clear_delayed_ () + { + // Remove the objects from the session cache. + // + for (typename delayed_loads::iterator i (delayed_.begin ()), + e (delayed_.end ()); i != e; ++i) + { + pointer_cache_traits::erase (i->pos); + } + + delayed_.clear (); + } + } +} diff --git a/libodb-mssql/odb/mssql/statement-cache.hxx b/libodb-mssql/odb/mssql/statement-cache.hxx new file mode 100644 index 0000000..cf06b94 --- /dev/null +++ b/libodb-mssql/odb/mssql/statement-cache.hxx @@ -0,0 +1,59 @@ +// file : odb/mssql/statement-cache.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_STATEMENT_CACHE_HXX +#define ODB_MSSQL_STATEMENT_CACHE_HXX + +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class LIBODB_MSSQL_EXPORT statement_cache + { + public: + statement_cache (connection& conn) + : conn_ (conn), + version_seq_ (conn_.database ().schema_version_sequence ()) {} + + template + typename object_traits_impl::statements_type& + find_object (); + + template + view_statements& + find_view (); + + private: + typedef std::map, + details::type_info_comparator> map; + + connection& conn_; + unsigned int version_seq_; + map map_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_STATEMENT_CACHE_HXX diff --git a/libodb-mssql/odb/mssql/statement-cache.txx b/libodb-mssql/odb/mssql/statement-cache.txx new file mode 100644 index 0000000..84424e3 --- /dev/null +++ b/libodb-mssql/odb/mssql/statement-cache.txx @@ -0,0 +1,60 @@ +// file : odb/mssql/statement-cache.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +namespace odb +{ + namespace mssql + { + template + typename object_traits_impl::statements_type& + statement_cache:: + find_object () + { + typedef + typename object_traits_impl::statements_type + statements_type; + + // Clear the cache if the database version has changed. This + // makes sure we don't re-use statements that correspond to + // the old schema. + // + if (version_seq_ != conn_.database ().schema_version_sequence ()) + { + map_.clear (); + version_seq_ = conn_.database ().schema_version_sequence (); + } + + map::iterator i (map_.find (&typeid (T))); + + if (i != map_.end ()) + return static_cast (*i->second); + + details::shared_ptr p ( + new (details::shared) statements_type (conn_)); + + map_.insert (map::value_type (&typeid (T), p)); + return *p; + } + + template + view_statements& statement_cache:: + find_view () + { + // We don't cache any statements for views so no need to clear + // the cache. + + map::iterator i (map_.find (&typeid (T))); + + if (i != map_.end ()) + return static_cast&> (*i->second); + + details::shared_ptr > p ( + new (details::shared) view_statements (conn_)); + + map_.insert (map::value_type (&typeid (T), p)); + return *p; + } + } +} diff --git a/libodb-mssql/odb/mssql/statement-processing.cxx b/libodb-mssql/odb/mssql/statement-processing.cxx new file mode 100644 index 0000000..0c3072a --- /dev/null +++ b/libodb-mssql/odb/mssql/statement-processing.cxx @@ -0,0 +1,356 @@ +// file : odb/mssql/statement-processing.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +#include + +#ifdef LIBODB_TRACE_STATEMENT_PROCESSING +# include +#endif + +#include + +using namespace std; + +namespace odb +{ + namespace mssql + { + typedef bind bind_type; + + void statement:: + process_select (std::string& r, + const char* s, + const bind_type* bind, + std::size_t bind_size, +#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING + bool optimize +#else + bool +#endif + ) + { + // This implementation is pretty much the same as the generic one + // except for two things: + // + // 1. When checking for the fast case, take into account long data + // columns which we may have to re-arrange. + // + // 2. Create the column list in two passes, ordinary columns first + // followed by the long data columns. + // + + bool empty (true); // Empty case (if none present). + bool fast (true); // Fast case (if all present and none are long data). + for (size_t i (0); i != bind_size && (empty || fast); ++i) + { + const bind_type& b (bind[i]); + + if (b.buffer != 0) + empty = false; + else + fast = false; + + if (b.type == bind_type::long_string || + b.type == bind_type::long_nstring || + b.type == bind_type::long_binary) + fast = false; + } + + // Empty. + // + if (empty) + { + r.clear (); + +#ifdef LIBODB_TRACE_STATEMENT_PROCESSING + if (*s != '\0') + cerr << endl + << "old: '" << s << "'" << endl << endl + << "new: '" << r << "'" << endl << endl; +#endif + return; + } + + // Fast path: just remove the "structure". + // +#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING + if (fast && !optimize) + { + process_fast (s, r); + return; + } +#endif + + // Scan the statement and store the positions of various parts. + // + size_t n (traits::length (s)); + const char* e (s + n); + + // Header. + // + const char* p (find (s, e, '\n')); + assert (p != 0); + size_t header_size (p - s); + p++; + + // Column list. + // + const char* columns_begin (p); + for (const char* ce (comma_begin (p, e)); ce != 0; comma_next (p, ce, e)) + ; + + // FROM. + assert (traits::compare (p, "FROM ", 5) == 0); + const char* from_begin (p); + p = find (p, e, '\n'); // May not end with '\n'. + if (p == 0) + p = e; + size_t from_size (p - from_begin); + if (p != e) + p++; + + // JOIN list. + // + const char* joins_begin (0), *joins_end (0); + if (e - p > 5 && fuzzy_prefix (p, e, "JOIN ", 5)) + { + joins_begin = p; + + // Find the end of the JOIN list. + // + for (const char* je (newline_begin (p, e)); + je != 0; newline_next (p, je, e, "JOIN ", 5, true)) + ; + + joins_end = (p != e ? p - 1 : p); + } + +#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING + if (fast && joins_begin == 0) + { + // No JOINs to optimize so can still take the fast path. + // + process_fast (s, r); + return; + } +#endif + + // Trailer (WHERE, ORDER BY, etc). + // + const char* trailer_begin (0); + size_t trailer_size (0); + if (e - p != 0) + { + trailer_begin = p; + trailer_size = e - p; + } + + // Assume the same size as the original. It can only shrink, and in + // most cases only slightly. So this is a good approximation. + // + r.reserve (n); + r.assign (s, header_size); + + // Column list. + // + { + r += ' '; + + size_t i (0); + bool need_second (false); + + // First pass: non-long data columns. + // + { + size_t bi (0); + for (const char *c (columns_begin), *ce (comma_begin (c, e)); + ce != 0; comma_next (c, ce, e)) + { + const bind_type& b (bind[bi++]); + + // See if the column is present in the bind array and if it + // is of the right kind. + // + if (b.buffer == 0) + continue; + + if (b.type == bind_type::long_string || + b.type == bind_type::long_nstring || + b.type == bind_type::long_binary) + { + need_second = true; + continue; + } + + // Append the column. + // + if (i++ != 0) + r += ", "; // Add the space for consistency with the fast path. + + r.append (c, ce - c); + } + } + + // Second pass: long data columns. + // + if (need_second) + { + size_t bi (0); + for (const char *c (columns_begin), *ce (comma_begin (c, e)); + ce != 0; comma_next (c, ce, e)) + { + const bind_type& b (bind[bi++]); + + // See if the column is present in the bind array and if it + // is of the right kind. + // + if (b.buffer == 0 || + (b.type != bind_type::long_string && + b.type != bind_type::long_nstring && + b.type != bind_type::long_binary)) + continue; + + // Append the column. + // + if (i++ != 0) + r += ", "; // Add the space for consistency with the fast path. + + r.append (c, ce - c); + } + } + } + + // From. + // + r += ' '; + r.append (from_begin, from_size); + + // JOIN list, pass 1. + // + size_t join_pos (0); + if (joins_begin != 0) + { + // Fill in the JOIN "area" with spaces. + // + r.resize (r.size () + joins_end - joins_begin + 1, ' '); + join_pos = r.size () + 1; // End of the last JOIN. + } + + // Trailer. + // + if (trailer_size != 0) + { + r += ' '; + r.append (trailer_begin, trailer_size); + } + + // JOIN list, pass 2. + // + if (joins_begin != 0) + { + // Splice the JOINs into the pre-allocated area. + // + for (const char* je (joins_end), *j (newline_rbegin (je, joins_begin)); + j != 0; newline_rnext (j, je, joins_begin)) + { + size_t n (je - j); + + // Get the alias or, if none used, the table name. + // + p = find (j, je, "JOIN ", 5) + 5; // Skip past "JOIN ". + const char* table_begin (p); + p = find (p, je, ' '); // End of the table name. + const char* table_end (p); + p++; // Skip space. + + // We may or may not have the AS keyword. + // + const char* alias_begin (0); + size_t alias_size (0); + if (p != je && // Not the end. + (je - p < 4 || traits::compare (p, "ON ", 3) != 0)) + { + // Something other than "ON ", so got to be an alias. + // + p += 3; + alias_begin = p; + p = find (p, je, ' '); // There might be no ON (CROSS JOIN). + alias_size = (p != 0 ? p : je) - alias_begin; + } + else + { + // Just the table. + // + alias_begin = table_begin; + alias_size = table_end - alias_begin; + } + + // The alias must be quoted. + // + assert (*alias_begin == '[' && + *(alias_begin + alias_size - 1) == ']'); + + // We now need to see if the alias is used in either the SELECT + // list, the WHERE conditions, or the ON condition of any of the + // JOINs that we have already processed and decided to keep. + // + // Instead of re-parsing the whole thing again, we are going to + // take a shortcut and simply search for the alias in the statement + // we have constructed so far (that's why we have added the + // trailer before filling in the JOINs). To make it more robust, + // we are going to do a few extra sanity checks, specifically, + // that the alias is a top level identifier and is followed by + // only a single identifer (column). This will catch cases like + // [s].[t].[c] where [s] is also used as an alias or LEFT JOIN [t] + // where [t] is also used as an alias in another JOIN. + // + bool found (false); + for (size_t p (r.find (alias_begin, 0, alias_size)); + p != string::npos; + p = r.find (alias_begin, p + alias_size, alias_size)) + { + size_t e (p + alias_size); + + // If we are not a top-level qualifier or not a bottom-level, + // then we are done (3 is for at least "[a]"). + // + if ((p != 0 && r[p - 1] == '.') || + (e + 3 >= r.size () || (r[e] != '.' || r[e + 1] != '['))) + continue; + + // The only way to distinguish the [a].[c] from FROM [a].[c] or + // JOIN [a].[c] is by checking the prefix. + // + if ((p > 5 && r.compare (p - 5, 5, "FROM ") == 0) || + (p > 5 && r.compare (p - 5, 5, "JOIN ") == 0)) + continue; + + // Check that we are followed by a single identifier. + // + e = r.find (']', e + 2); + if (e == string::npos || (e + 1 != r.size () && r[e + 1] == '.')) + continue; + + found = true; + break; + } + + join_pos -= n + 1; // Extra one for space. + if (found) + r.replace (join_pos, n, j, n); + else + r.erase (join_pos - 1, n + 1); // Extra one for space. + } + } + +#ifdef LIBODB_TRACE_STATEMENT_PROCESSING + if (r.size () != n) + cerr << endl + << "old: '" << s << "'" << endl << endl + << "new: '" << r << "'" << endl << endl; +#endif + } + } +} diff --git a/libodb-mssql/odb/mssql/statement.cxx b/libodb-mssql/odb/mssql/statement.cxx new file mode 100644 index 0000000..ede4bb6 --- /dev/null +++ b/libodb-mssql/odb/mssql/statement.cxx @@ -0,0 +1,1740 @@ +// file : odb/mssql/statement.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::strlen, std::strstr, std::memset, std::memcpy +#include + +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace odb +{ + namespace mssql + { + // Mapping of bind::buffer_type to SQL_* SQL types. + // + static const SQLSMALLINT sql_type_lookup [bind::last] = + { + SQL_BIT, // bind::bit + SQL_TINYINT, // bind::tinyint + SQL_SMALLINT, // bind::smallint + SQL_INTEGER, // bind::int_ + SQL_BIGINT, // bind::bigint + + SQL_DECIMAL, // bind::decimal + SQL_DECIMAL, // bind::smallmoney + SQL_DECIMAL, // bind::money + + SQL_FLOAT, // bind::float4 + SQL_FLOAT, // bind::float8 + + SQL_VARCHAR, // bind::string + SQL_VARCHAR, // bind::long_string + + SQL_WVARCHAR, // bind::nstring + SQL_WVARCHAR, // bind::long_nstring + + SQL_VARBINARY, // bind::binary + SQL_VARBINARY, // bind::long_binary + + SQL_TYPE_DATE, // bind::date + SQL_SS_TIME2, // bind::time + SQL_TYPE_TIMESTAMP, // bind::datetime + SQL_SS_TIMESTAMPOFFSET, // bind::datetimeoffset + + SQL_GUID, // bind::uniqueidentifier + SQL_BINARY // bind::rowversion + }; + + // Mapping of bind::buffer_type to SQL_C_* C types. + // + static const SQLSMALLINT c_type_lookup [bind::last] = + { + SQL_C_BIT, // bind::bit + SQL_C_UTINYINT, // bind::tinyint + SQL_C_SSHORT, // bind::smallint + SQL_C_SLONG, // bind::int_ + SQL_C_SBIGINT, // bind::bigint + + SQL_C_NUMERIC, // bind::decimal + SQL_C_BINARY, // bind::smallmoney + SQL_C_BINARY, // bind::money + + SQL_C_FLOAT, // bind::float4 + SQL_C_DOUBLE, // bind::float8 + + SQL_C_CHAR, // bind::string + SQL_C_CHAR, // bind::long_string + + SQL_C_WCHAR, // bind::nstring + SQL_C_WCHAR, // bind::long_nstring + + SQL_C_BINARY, // bind::binary + SQL_C_BINARY, // bind::long_binary + + SQL_C_TYPE_DATE, // bind::date + SQL_C_BINARY, // bind::time + SQL_C_TYPE_TIMESTAMP, // bind::datetime + SQL_C_BINARY, // bind::datetimeoffset + + SQL_C_GUID, // bind::uniqueidentifier + SQL_C_BINARY // bind::rowversion + }; + + // Mapping of bind::buffer_type to fixed buffer capacity values. + // + static const SQLLEN capacity_lookup [bind::last] = + { + 1, // bind::bit + 1, // bind::tinyint + 2, // bind::smallint + 4, // bind::int_ + 8, // bind::bigint + + sizeof (decimal), // bind::decimal + 4, // bind::smallmoney + 8, // bind::money + + 4, // bind::float4 + 8, // bind::float8 + + 0, // bind::string + 0, // bind::long_string + + 0, // bind::nstring + 0, // bind::long_nstring + + 0, // bind::binary + 0, // bind::long_binary + + sizeof (date), // bind::date + sizeof (time), // bind::time + sizeof (datetime), // bind::datetime + sizeof (datetimeoffset), // bind::datetimeoffset + + 16, // bind::uniqueidentifier + 8 // bind::rowversion + }; + + // + // statement + // + + statement:: + statement (connection_type& conn, + const string& text, + statement_kind sk, + const binding* process, + bool optimize) + : conn_ (conn) + { + if (process == 0) + { + text_copy_ = text; + text_ = text_copy_.c_str (); + } + else + text_ = text.c_str (); // Temporary, see init(). + + init (text.size (), sk, process, optimize); + } + + statement:: + statement (connection_type& conn, + const char* text, + statement_kind sk, + const binding* process, + bool optimize, + bool copy) + : conn_ (conn) + { + size_t n; + + if (process == 0 && copy) + { + text_copy_ = text; + text_ = text_copy_.c_str (); + n = text_copy_.size (); + } + else + { + text_ = text; + n = strlen (text_); // Potentially temporary, see init(). + } + + init (n, sk, process, optimize); + } + + void statement:: + init (size_t text_size, + statement_kind sk, + const binding* proc, + bool optimize) + { + if (proc != 0) + { + switch (sk) + { + case statement_select: + process_select (text_copy_, + text_, + proc->bind, proc->count, + optimize); + break; + case statement_insert: + process_insert (text_copy_, + text_, + &proc->bind->buffer, proc->count, sizeof (bind), + '?'); + break; + case statement_update: + process_update (text_copy_, + text_, + &proc->bind->buffer, proc->count, sizeof (bind), + '?'); + break; + case statement_delete: + assert (false); + } + + text_ = text_copy_.c_str (); + text_size = text_copy_.size (); + } + + // Empty statement. + // + if (*text_ == '\0') + return; + + SQLRETURN r; + + // Allocate the handle. + // + { + SQLHANDLE h; + r = SQLAllocHandle (SQL_HANDLE_STMT, conn_.handle (), &h); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_); + + stmt_.reset (h); + } + + // Disable escape sequences. + // + r = SQLSetStmtAttr (stmt_, + SQL_ATTR_NOSCAN, + (SQLPOINTER) SQL_NOSCAN_OFF, + 0); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + { + odb::tracer* t; + if ((t = conn_.transaction_tracer ()) || + (t = conn_.tracer ()) || + (t = conn_.database ().tracer ())) + t->prepare (conn_, *this); + } + + // Prepare the statement. + // + r = SQLPrepareA (stmt_, (SQLCHAR*) text_, (SQLINTEGER) text_size); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + + statement:: + ~statement () + { + if (stmt_ != 0) + { + odb::tracer* t; + if ((t = conn_.transaction_tracer ()) || + (t = conn_.tracer ()) || + (t = conn_.database ().tracer ())) + t->deallocate (conn_, *this); + } + } + + const char* statement:: + text () const + { + return text_; + } + + void statement:: + bind_param (bind* b, size_t n) + { + SQLRETURN r; + + SQLUSMALLINT i (0); + for (bind* end (b + n); b != end; ++b) + { + if (b->buffer == 0) // Skip NULL entries. + continue; + + i++; // Column index is 1-based. + + SQLULEN col_size (0); + SQLSMALLINT digits (0); + SQLPOINTER buf; + + switch (b->type) + { + case bind::decimal: + { + buf = (SQLPOINTER) b->buffer; + col_size = (SQLULEN) (b->capacity / 100); // precision + digits = (SQLSMALLINT) (b->capacity % 100); // scale + break; + } + case bind::smallmoney: + { + buf = (SQLPOINTER) b->buffer; + col_size = 10; + digits = 4; + break; + } + case bind::money: + { + buf = (SQLPOINTER) b->buffer; + col_size = 19; + digits = 4; + break; + } + case bind::float4: + case bind::float8: + { + buf = (SQLPOINTER) b->buffer; + col_size = (SQLULEN) b->capacity; // precision + break; + } + case bind::long_string: + case bind::long_binary: + { + buf = (SQLPOINTER) b->buffer; + col_size = b->capacity != 0 + ? (SQLULEN) b->capacity + : SQL_SS_LENGTH_UNLIMITED; + break; + } + case bind::long_nstring: + { + buf = (SQLPOINTER) b->buffer; + col_size = b->capacity != 0 + ? (SQLULEN) b->capacity / 2 // In characters, not bytes. + : SQL_SS_LENGTH_UNLIMITED; + break; + } + case bind::string: + { + buf = (SQLPOINTER) b->buffer; + col_size = b->capacity != 0 + ? (SQLULEN) b->capacity - 1 // Sans the null-terminator. + : SQL_SS_LENGTH_UNLIMITED; + break; + } + case bind::binary: + { + buf = (SQLPOINTER) b->buffer; + col_size = b->capacity != 0 + ? (SQLULEN) b->capacity + : SQL_SS_LENGTH_UNLIMITED; + break; + } + case bind::nstring: + { + buf = (SQLPOINTER) b->buffer; + col_size = b->capacity != 0 + // In characters, not bytes, and sans the null-terminator. + ? (SQLULEN) (b->capacity / 2 - 1) + : SQL_SS_LENGTH_UNLIMITED; + break; + } + case bind::date: + { + buf = (SQLPOINTER) b->buffer; + // Native Client 10.0 requires the correct precision. + // + col_size = 10; + break; + } + case bind::time: + { + buf = (SQLPOINTER) b->buffer; + digits = (SQLSMALLINT) b->capacity; + + // Native Client 10.0 requires the correct precision. + // + if (digits == 0) + col_size = 8; + else + col_size = (SQLULEN) (digits + 9); + + break; + } + case bind::datetime: + { + buf = (SQLPOINTER) b->buffer; + digits = (SQLSMALLINT) b->capacity; + + // Native Client 10.0 requires the correct precision. + // + if (digits == 0) + col_size = 19; + else if (digits == 8) + { + // This is a SMALLDATETIME column which only has the minutes + // precision. Documentation indicates that the correct numeric + // precision value for this type is 16. + // + digits = 0; + col_size = 16; + } + else + col_size = (SQLULEN) (digits + 20); + + break; + } + case bind::datetimeoffset: + { + buf = (SQLPOINTER) b->buffer; + digits = (SQLSMALLINT) b->capacity; + + // Native Client 10.0 requires the correct precision. + // + if (digits == 0) + col_size = 26; + else + col_size = (SQLULEN) (digits + 27); + + break; + } + case bind::rowversion: + { + buf = (SQLPOINTER) b->buffer; + col_size = 8; + break; + } + default: + { + buf = (SQLPOINTER) b->buffer; + break; + } + } + + r = SQLBindParameter ( + stmt_, + i, + SQL_PARAM_INPUT, + c_type_lookup[b->type], + sql_type_lookup[b->type], + col_size, + digits, + buf, + 0, // buffer capacity (shouldn't be needed for input parameters) + b->size_ind); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + } + + SQLUSMALLINT statement:: + bind_result (bind* b, size_t n, SQLUSMALLINT& long_count) + { + long_count = 0; + SQLRETURN r; + + SQLUSMALLINT i (0); + for (bind* end (b + n); b != end; ++b) + { + if (b->buffer == 0) // Skip NULL entries. + continue; + + SQLLEN cap (capacity_lookup[b->type]); + + switch (b->type) + { + case bind::string: + case bind::nstring: + case bind::binary: + { + cap = b->capacity; + break; + } + case bind::long_string: + case bind::long_nstring: + case bind::long_binary: + { + // Long data is not bound. + // + long_count++; + continue; + } + case bind::last: + { + assert (false); + break; + } + default: + break; + } + + r = SQLBindCol (stmt_, + ++i, // Column index is 1-based. + c_type_lookup[b->type], + (SQLPOINTER) b->buffer, + cap, + b->size_ind); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + + return i; + } + + SQLRETURN statement:: + execute () + { + { + odb::tracer* t; + if ((t = conn_.transaction_tracer ()) || + (t = conn_.tracer ()) || + (t = conn_.database ().tracer ())) + t->execute (conn_, *this); + } + + SQLRETURN r (SQLExecute (stmt_)); + + if (r == SQL_NEED_DATA) + { + details::buffer& tmp_buf (conn_.long_data_buffer ()); + + if (tmp_buf.capacity () == 0) + tmp_buf.capacity (4096); + + long_callback* pcb; + for (;;) + { + // ODBC seems to already offset the returned pointer for us + // in case of a batch. + // + r = SQLParamData (stmt_, (SQLPOINTER*) &pcb); + + // If we get anything other than SQL_NEED_DATA, then this is + // the return code of SQLExecute(). + // + if (r != SQL_NEED_DATA) + break; + + // Store the pointer to the long_callback struct in buf on the + // first call to the callback. This allows the callback to + // redirect further calls to some other callback. + // + long_callback cb (*pcb); + const void* buf (&cb); + + size_t position (0); + for (;;) + { + size_t n; + chunk_type chunk; + + cb.callback.param ( + cb.context.param, + &position, + &buf, + &n, + &chunk, + tmp_buf.data (), + tmp_buf.capacity ()); + + r = SQLPutData ( + stmt_, + (SQLPOINTER) (buf != 0 ? buf : &buf), // Always pass non-NULL. + chunk != chunk_null ? (SQLLEN) n : SQL_NULL_DATA); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + if (chunk == chunk_one || + chunk == chunk_last || + chunk == chunk_null) + break; + } + } + } + + return r; + } + + void statement:: + stream_result (SQLUSMALLINT i, bind* b, size_t n, void* obase, void* nbase) + { + details::buffer& tmp_buf (conn_.long_data_buffer ()); + + if (tmp_buf.capacity () == 0) + tmp_buf.capacity (4096); + + SQLRETURN r; + + for (bind* end (b + n); b != end; ++b) + { + if (b->buffer == 0) // Skip NULL entries. + continue; + + bool char_data; + switch (b->type) + { + case bind::long_string: + case bind::long_nstring: + { + char_data = true; + break; + } + case bind::long_binary: + { + char_data = false; + break; + } + default: + { + continue; // Not long data. + } + } + + void* cbp; + + if (obase == 0) + cbp = b->buffer; + else + { + // Re-base the pointer. + // + char* p (static_cast (b->buffer)); + char* ob (static_cast (obase)); + char* nb (static_cast (nbase)); + + assert (ob <= p); + cbp = nb + (p - ob); + } + + long_callback cb (*static_cast (cbp)); + + // First determine if the value is NULL as well as try to + // get the total data size. + // + SQLLEN si; + r = SQLGetData (stmt_, + ++i, + c_type_lookup[b->type], + tmp_buf.data (), // Dummy value. + 0, + &si); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + // Store the pointer to the long_callback struct in buf on the + // first call to the callback. This allows the callback to + // redirect further calls to some other callback. + // + void* buf (&cb); + size_t size (0); + size_t position (0); + size_t size_left (si == SQL_NO_TOTAL ? 0 : static_cast (si)); + + chunk_type c (si == SQL_NULL_DATA + ? chunk_null + : (si == 0 ? chunk_one : chunk_first)); + + for (;;) + { + cb.callback.result ( + cb.context.result, + &position, + &buf, + &size, + c, + size_left, + tmp_buf.data (), + tmp_buf.capacity ()); + + if (c == chunk_last || c == chunk_one || c == chunk_null) + break; + + // SQLGetData() can keep returning SQL_SUCCESS_WITH_INFO (truncated) + // with SQL_NO_TOTAL for all the calls except the last one. For the + // last call we should get SQL_SUCCESS and the size_indicator should + // contain a valid value. + // + r = SQLGetData (stmt_, + i, + c_type_lookup[b->type], + (SQLPOINTER) buf, + (SQLLEN) size, + &si); + + if (r == SQL_SUCCESS) + { + assert (si != SQL_NO_TOTAL); + + // Actual amount of data copied to the buffer (appears not to + // include the NULL terminator). + // + size = static_cast (si); + c = chunk_last; + } + else if (r == SQL_SUCCESS_WITH_INFO) + { + if (char_data) + size--; // NULL terminator. + + c = chunk_next; + } + else + translate_error (r, conn_, stmt_); + + // Update the total. + // + if (size_left != 0) + size_left -= size; + } + } + } + + // + // bulk_statement + // + bulk_statement:: + ~bulk_statement () {} + + void bulk_statement:: + init (size_t skip) + { + // Setup row-wise batch operation. We set the actual number of + // parameter sets in the batch in execute(). + // + SQLRETURN r; + + r = SQLSetStmtAttr (stmt_, + SQL_ATTR_PARAM_BIND_TYPE, + (SQLPOINTER) skip, + 0); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + r = SQLSetStmtAttr (stmt_, + SQL_ATTR_PARAMS_PROCESSED_PTR, + (SQLPOINTER) &processed_, + 0); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + r = SQLSetStmtAttr (stmt_, + SQL_ATTR_PARAM_STATUS_PTR, + (SQLPOINTER) status_, + 0); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + + SQLRETURN bulk_statement:: + execute (size_t n, multiple_exceptions* mex) + { + mex_ = mex; + + if (status_ != 0) + { + SQLRETURN r (SQLSetStmtAttr (stmt_, + SQL_ATTR_PARAMSET_SIZE, + (SQLPOINTER) n, + 0)); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + // Some SQL* functions would only update the status in case of + // an error. + // + memset (status_, 0, sizeof (status_[0]) * n); + } + + processed_ = 0; + SQLRETURN r (statement::execute ()); + bool ok (SQL_SUCCEEDED (r) || r == SQL_NO_DATA); + + // If we have a batch of 1 parameter set, SQL Server ODBC driver + // returns the error via SQLExecute() rather than via the status + // array even if we set all the attributes necessary for row-wise + // binding. So what we are going to do here is convert this case + // to the batch way of reporting errors (not that we also check + // processed_ so that we only do this is the parameter set was + // actually attempted). + // + if (!ok && status_ != 0 && n == 1 && processed_ == 1) + { + status_[0] = SQL_PARAM_ERROR; + r = SQL_SUCCESS; + ok = true; + } + + // If the statement failed as a whole, assume no parameter sets + // were attempted in case of a batch. Otherwise, the documentation + // says that the native client driver keeps processing remaining + // sets even in case of an error. + // + i_ = 0; + n_ = (ok ? n : (status_ == 0 ? 1 : 0)); + + if (mex_ != 0) + { + mex_->current (i_); + mex_->attempted (processed_); + } + + if (!ok) + { + if (mex_ != 0) + mex_->fatal (true); // An incomplete batch is always fatal. + + return r; + } + + return r; + } + + size_t bulk_statement:: + extract_errors () + { + size_t e (0); + + for (size_t i (0); i != n_; ++i) + { + if (status_[i] != SQL_PARAM_SUCCESS && + status_[i] != SQL_PARAM_SUCCESS_WITH_INFO) + { + translate_error (SQL_ERROR, conn_, stmt_, i, mex_); + e++; + } + } + + return e; + } + + unsigned long long bulk_statement:: + affected (SQLRETURN r, size_t errors, bool unique) + { + unsigned long long rows (0); + + // SQL_NO_DATA indicates that the statement hasn't affected any rows. + // + if (r != SQL_NO_DATA) + { + SQLLEN n; + r = SQLRowCount (stmt_, &n); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + // If all the parameter sets failed, then the returned count is -1, + // which means "not available" according to the documentation. + // + rows = (n != -1 ? static_cast (n) : 0); + } + + if (n_ > 1) // Batch. + { + if (rows != 0) // Some rows did get affected. + { + // Subtract the parameter sets that failed since they haven't + // affected any rows. + // + size_t p (n_ - errors); + + if (p > 1) // True batch. + { + if (unique) // Each can affect 0 or 1 row. + { + rows = (p == static_cast (rows) + ? 1 + : result_unknown); + } + else + rows = result_unknown; + } + } + } + + return rows; + } + + // + // select_statement + // + select_statement:: + ~select_statement () + { + } + + select_statement:: + select_statement (connection_type& conn, + const string& text, + bool process, + bool optimize, + binding& param, + binding& result) + : statement (conn, + text, statement_select, + (process ? &result : 0), optimize), + result_ (result) + { + if (!empty ()) + { + bind_param (param.bind, param.count); + result_count_ = bind_result (result.bind, result.count, long_count_); + } + } + + select_statement:: + select_statement (connection_type& conn, + const char* text, + bool process, + bool optimize, + binding& param, + binding& result, + bool copy_text) + : statement (conn, + text, statement_select, + (process ? &result : 0), optimize, + copy_text), + result_ (result) + { + if (!empty ()) + { + bind_param (param.bind, param.count); + result_count_ = bind_result (result.bind, result.count, long_count_); + } + } + + select_statement:: + select_statement (connection_type& conn, + const string& text, + bool process, + bool optimize, + binding& result) + : statement (conn, + text, statement_select, + (process ? &result : 0), optimize), + result_ (result) + { + if (!empty ()) + result_count_ = bind_result (result.bind, result.count, long_count_); + } + + select_statement:: + select_statement (connection_type& conn, + const char* text, + bool process, + bool optimize, + binding& result, + bool copy_text) + : statement (conn, + text, statement_select, + (process ? &result : 0), optimize, + copy_text), + result_ (result) + { + if (!empty ()) + result_count_ = bind_result (result.bind, result.count, long_count_); + } + + void select_statement:: + execute () + { + SQLRETURN r (statement::execute ()); + + // Skip empty result sets that seem to be added as a result of + // executing DML statements in stored procedures (e.g., INSERT + // INTO EXEC). + // + if (r == SQL_NO_DATA) + { + r = SQLMoreResults (stmt_); + + if (r == SQL_NO_DATA) + { + throw database_exception ( + 0, + "?????", + "another result set expected after SQL_NO_DATA"); + } + } + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + // Skip result sets that have no columns. These seem to be added + // by DML statements that don't produce any result (e.g., EXEC). + // + for (columns_ = 0; columns_ == 0;) + { + { + SQLSMALLINT c; + r = SQLNumResultCols (stmt_, &c); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + columns_ = static_cast (c); + } + + if (columns_ == 0) + { + r = SQLMoreResults (stmt_); + + if (r == SQL_NO_DATA) + break; + else if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + } + + // Make sure that the number of columns in the result returned by + // the database matches the number that we expect. A common cause + // of this assertion is a native view with a number of data members + // not matching the number of columns in the SELECT-list. + // + assert (columns_ == result_count_ + long_count_); + } + + select_statement::result select_statement:: + fetch () + { + change_callback* cc (result_.change_callback); + + if (cc != 0 && cc->callback != 0) + (cc->callback) (cc->context); + + // Don't bother calling SQLFetch() if there are no columns. + // + if (columns_ == 0) + return no_data; + else + { + SQLRETURN r (SQLFetch (stmt_)); + + if (r == SQL_NO_DATA) + return no_data; + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + return success; + } + } + + void select_statement:: + free_result () + { + // Use SQLFreeStmt(SQL_CLOSE) instead of SQLCloseCursor() to avoid an + // error if a cursor is already closed. This can happens, for example, + // if we are trying to close the cursor after the transaction has been + // committed (e.g., when destroying the query result) which also closes + // the cursor. + // + SQLRETURN r (SQLFreeStmt (stmt_, SQL_CLOSE)); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + + // + // insert_statement + // + + insert_statement:: + ~insert_statement () + { + } + + insert_statement:: + insert_statement (connection_type& conn, + const string& text, + bool process, + binding& param, + bool returning_id, + bool returning_version, + binding* returning) + : bulk_statement (conn, + text, statement_insert, + (process ? ¶m : 0), false, + param.batch, param.skip, param.status), + returning_id_ (returning_id), + returning_version_ (returning_version), + ret_ (returning) + { + bind_param (param.bind, param.count); + + if (ret_ != 0) + init_result (); + } + + insert_statement:: + insert_statement (connection_type& conn, + const char* text, + bool process, + binding& param, + bool returning_id, + bool returning_version, + binding* returning, + bool copy_text) + : bulk_statement (conn, + text, statement_insert, + (process ? ¶m : 0), false, + param.batch, param.skip, param.status, + copy_text), + returning_id_ (returning_id), + returning_version_ (returning_version), + ret_ (returning) + { + bind_param (param.bind, param.count); + + if (ret_ != 0) + init_result (); + } + + template + static inline T* + offset (T* base, size_t count, size_t size) + { + return reinterpret_cast ( + reinterpret_cast (base) + count * size); + } + + void insert_statement:: + init_result () + { + // Figure out if we are using the OUTPUT clause or a batch of + // INSERT and SELECT statements. The latter is used to work + // around a bug in SQL Server 2005 that causes it to fail + // on an INSERT statement with the OUTPUT clause if data + // for one of the inserted columns is supplied at execution + // (long data). + // + text_batch_ = (strstr (text_, "OUTPUT INSERTED.") == 0 && + strstr (text_, "output inserted.") == 0); + + // It might seem logical to set up the array of results if this is a + // batch (i.e., the SQL_ATTR_ROW_BIND_TYPE, SQL_ATTR_ROW_ARRAY_SIZE). + // This won't work because what we are getting is multiple result + // sets (each containing a single row) and not multiple rows. As a + // result, the SQL Server ODBC driver will always store the data in + // the first element of our array. A bit counter-intuitive. + // + // At the same time it would be conceptually cleaner to have the + // returned data extracted into the batch array instead of always + // the first element. This is also how other database runtimes (e.g., + // Oracle) behave. So what we are going to do here is emulate this + // by making the ODBC driver store the data into the last element + // of the batch array and then copying it into the right place + // after processing each result set (see fetch() below). + // + SQLRETURN r; + SQLUSMALLINT col (1); + + size_t last (ret_->batch - 1); + + if (returning_id_) + { + bind& b (ret_->bind[0]); // Auto id is the first element. + + r = SQLBindCol (stmt_, + col++, + c_type_lookup[b.type], + (SQLPOINTER) offset (b.buffer, last, ret_->skip), + capacity_lookup[b.type], + offset (b.size_ind, last, ret_->skip)); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + + if (returning_version_) + { + bind& b (ret_->bind[ret_->count - 1]); // Version is the last element. + + r = SQLBindCol (stmt_, + col++, + c_type_lookup[b.type], + (SQLPOINTER) offset (b.buffer, last, ret_->skip), + capacity_lookup[b.type], + offset (b.size_ind, last, ret_->skip)); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + } + + size_t insert_statement:: + execute (size_t n, multiple_exceptions* mex) + { + // The batch INSERT works in two different ways, depending on + // whether we have the OUTPUT clause. If there is no OUTPUT, then + // all the parameter sets are processed inside the SQLExecute() + // call. If, however, there is OUTPUT, then the sets are + // processed one at a time as we consume the results with + // the SQLMoreResults() call below. Thus we in effect have + // two counts: the "processed so far" as set by the API + // (SQL_ATTR_PARAMS_PROCESSED_PTR) and the "to be processed" + // (value in n_). Note that in the OUTPUT case if there is an + // error, the processed count seems to jump by 2 for some reason. + // + // The OUTPUT case can be handled in two different ways: we can + // "execute" (with SQLMoreResults()) each set as the user moves + // from one result to the next (result() call). The advantage of + // this approach is that the returned data ends up in the right + // place automatically. The potential drawback is that the total + // affected row count will only be available at the end. As a + // result, this approach probably won't work if we need to handle, + // say, UPDATE with OUTPUT (SQLRowCount() does not return an + // intermediate total, at least not for INSERT). + // + // The alternative implementation would call SQLMoreResults() + // inside execute() until all the parameter sets are executed. + // In this case we will have to copy the extracted data into + // the right place in the bindings (or update the binding before + // each call to SQLMoreResults()). It is also not clear whether + // the diagnostic records for the failed sets would accumulate. + // If not, those will have to be stashed into mex on each + // iteration. + // + SQLRETURN r (bulk_statement::execute (n, mex)); + + // Statement failed as a whole, assume no parameter sets were + // attempted in case of a batch. + // + if (!SQL_SUCCEEDED (r)) + { + fetch (r); + return n_; + } + + if (status_ == 0) // Non-batch case. + fetch (SQL_SUCCESS); + else + fetch (status_[i_] == SQL_PARAM_SUCCESS || + status_[i_] == SQL_PARAM_SUCCESS_WITH_INFO + ? SQL_SUCCESS : SQL_ERROR); + + return n_; + } + + void insert_statement:: + fetch (SQLRETURN r) + { + result_ = true; + + if (!SQL_SUCCEEDED (r)) + { + // An auto-assigned object id should never cause a duplicate primary + // key. + // + if (!returning_id_) + { + // Translate the integrity contraint violation (SQLSTATE 23000) + // to the false result value. This code is similar to that found + // in translate_error(). + // + char sqlstate[SQL_SQLSTATE_SIZE + 1]; + SQLINTEGER native_code; + SQLSMALLINT msg_size; + + bool cv (false); + + for (SQLSMALLINT i (1);; ++i) + { + SQLRETURN r; + + // Filter based on row association. + // + if (mex_ != 0) + { + SQLLEN n; + r = SQLGetDiagField (SQL_HANDLE_STMT, + stmt_, + i, + SQL_DIAG_ROW_NUMBER, + &n, + 0, + 0); + + if (r == SQL_NO_DATA) + break; + else if (!SQL_SUCCEEDED (r)) + continue; + + if (n == SQL_NO_ROW_NUMBER || + n == SQL_ROW_NUMBER_UNKNOWN || + n != static_cast (i_ + 1)) // 1-based + continue; + } + + r= SQLGetDiagRecA (SQL_HANDLE_STMT, + stmt_, + i, + (SQLCHAR*) sqlstate, + &native_code, + 0, + 0, + &msg_size); + + if (r == SQL_NO_DATA) + break; + else if (SQL_SUCCEEDED (r)) + { + string s (sqlstate); + + if (s == "23000") // Integrity contraint violation. + cv = true; + else if (s != "01000") // General warning. + { + // Some other code. + // + cv = false; + break; + } + } + else // SQLGetDiagRec() failure. + { + cv = false; + break; + } + } + + if (cv) + result_ = false; + } + + if (result_) + { + translate_error (r, conn_, stmt_, i_, mex_); // Can return. + result_ = false; // Prevent id/version extraction below or. + } + } + + // Fetch the row containing the id/version if this statement is + // returning. + // + if (result_ && ret_ != 0) + { + if (text_batch_) + { + r = SQLMoreResults (stmt_); + + if (r == SQL_NO_DATA) + { + throw database_exception ( + 0, + "?????", + "multiple result sets expected from a batch of statements"); + } + else if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + + r = SQLFetch (stmt_); + + if (r != SQL_NO_DATA && !SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + if (r == SQL_NO_DATA) + throw database_exception ( + 0, + "?????", + "result set expected from a statement with the OUTPUT clause"); + + // See init_result() for details on what's going here. + // + size_t last (ret_->batch - 1); + if (i_ != last) + { + if (returning_id_) + { + bind& b (ret_->bind[0]); // Auto id is the first element. + + memcpy (offset (b.buffer, i_, ret_->skip), + offset (b.buffer, last, ret_->skip), + capacity_lookup[b.type]); + + memcpy (offset (b.size_ind, i_, ret_->skip), + offset (b.size_ind, last, ret_->skip), + sizeof (*b.size_ind)); + } + + if (returning_version_) + { + bind& b (ret_->bind[ret_->count - 1]); // Version is the last. + + memcpy (offset (b.buffer, i_, ret_->skip), + offset (b.buffer, last, ret_->skip), + capacity_lookup[b.type]); + + memcpy (offset (b.size_ind, i_, ret_->skip), + offset (b.size_ind, last, ret_->skip), + sizeof (*b.size_ind)); + } + } + } + } + + bool insert_statement:: + result (size_t i) + { + assert ((i_ == i || i_ + 1 == i) && i < n_); + + SQLRETURN r; + + // Get to the next result set if necessary. + // + if (i != i_) + { + mex_->current (++i_); // mex cannot be NULL since this is a batch. + + // Only in case of the OUTPUT clause do we have multiple result sets. + // + if (ret_ != 0) + { + r = SQLMoreResults (stmt_); + + // The actually processed count could have changed (see execute()). + // + mex_->attempted (processed_); + + if (r == SQL_NO_DATA) + { + throw database_exception ( + 0, + "?????", + "multiple result sets expected from an array of parameters"); + } + } + + fetch (status_[i_] == SQL_PARAM_SUCCESS || + status_[i_] == SQL_PARAM_SUCCESS_WITH_INFO + ? SQL_SUCCESS : SQL_ERROR); + } + + // Close the cursor if we are done. + // + if (ret_ != 0 && i_ + 1 == n_) + { + // Use SQLFreeStmt(SQL_CLOSE) instead of SQLCloseCursor() to avoid + // an error if a cursor is not open. This seem to happen if the + // statement failure was translated to a parameter set failure in + // bulk_statement for batches of one. + // + r = SQLFreeStmt (stmt_, SQL_CLOSE); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + + return result_; + } + + // + // update_statement + // + + update_statement:: + ~update_statement () + { + } + + update_statement:: + update_statement (connection_type& conn, + const string& text, + bool process, + binding& param, + binding* returning) + : bulk_statement (conn, + text, statement_update, + (process ? ¶m : 0), false, + param.batch, param.skip, param.status), + unique_ (false), + returning_ (returning != 0) + { + assert (param.batch == 1); // Specify unique_hint explicitly. + init (param, returning); + } + + update_statement:: + update_statement (connection_type& conn, + const string& text, + bool unique, + bool process, + binding& param, + binding* returning) + : bulk_statement (conn, + text, statement_update, + (process ? ¶m : 0), false, + param.batch, param.skip, param.status), + unique_ (unique), + returning_ (returning != 0) + { + init (param, returning); + } + + update_statement:: + update_statement (connection_type& conn, + const char* text, + bool process, + binding& param, + binding* returning, + bool copy_text) + : bulk_statement (conn, + text, statement_update, + (process ? ¶m : 0), false, + param.batch, param.skip, param.status, + copy_text), + unique_ (false), + returning_ (returning != 0) + { + assert (param.batch == 1); // Specify unique_hint explicitly. + init (param, returning); + } + + update_statement:: + update_statement (connection_type& conn, + const char* text, + bool unique, + bool process, + binding& param, + binding* returning, + bool copy_text) + : bulk_statement (conn, + text, statement_update, + (process ? ¶m : 0), false, + param.batch, param.skip, param.status, + copy_text), + unique_ (unique), + returning_ (returning != 0) + { + init (param, returning); + } + + void update_statement:: + init (binding& param, binding* ret) + { + if (!empty ()) + { + bind_param (param.bind, param.count); + + if (ret != 0) + { + bind& b (ret->bind[ret->count - 1]); // Version is the last element. + + SQLRETURN r (SQLBindCol (stmt_, + 1, + c_type_lookup[b.type], + (SQLPOINTER) b.buffer, + capacity_lookup[b.type], + b.size_ind)); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + } + } + + size_t update_statement:: + execute (size_t n, multiple_exceptions* mex) + { + // In batch UPDATE without the OUTPUT clause (which is the + // only kind we currently support) all the parameter sets + // are processed inside SQLExecute() and the total count of + // affected rows is available after it returns. + // + assert (!returning_ || status_ == 0); + + SQLRETURN r (bulk_statement::execute (n, mex)); + + // Statement failed as a whole, assume no parameter sets were + // attempted in case of a batch. + // + if (!(SQL_SUCCEEDED (r) || r == SQL_NO_DATA)) + { + translate_error (r, conn_, stmt_, 0, mex_); + return n_; + } + + if (status_ == 0) // Non-batch case. + { + // Fetch the row containing the data if this statement is + // returning. We still need to close the cursor even if we + // haven't updated any rows. + // + if (returning_) + { + r = SQLFetch (stmt_); + + if (r != SQL_NO_DATA && !SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + + // We have to get the result after fetching the OUTPUT data + // but before closing the cursor. + // + result_ = affected (SQL_SUCCESS, 0, unique_); + + { + SQLRETURN r (SQLCloseCursor (stmt_)); // Don't overwrite r. + + if (!SQL_SUCCEEDED (r)) + translate_error (r, conn_, stmt_); + } + + if (result_ != 0 && r == SQL_NO_DATA) + throw database_exception ( + 0, + "?????", + "result set expected from a statement with the OUTPUT clause"); + } + else + result_ = affected (r, 0, unique_); + } + else + { + // Extract error information for failed parameter sets. If we do + // this after calling SQLRowCount(), all the diagnostics records + // that we need will be gone. + // + size_t errors (extract_errors ()); + + // Figure out the affected row count. + // + result_ = affected (r, errors, unique_); + } + + return n_; + } + + // + // delete_statement + // + + delete_statement:: + ~delete_statement () + { + } + + delete_statement:: + delete_statement (connection_type& conn, + const string& text, + binding& param) + : bulk_statement (conn, + text, statement_delete, + 0, false, + param.batch, param.skip, param.status), + unique_ (false) + { + assert (param.batch == 1); // Specify unique_hint explicitly. + bind_param (param.bind, param.count); + } + + delete_statement:: + delete_statement (connection_type& conn, + const string& text, + bool unique, + binding& param) + : bulk_statement (conn, + text, statement_delete, + 0, false, + param.batch, param.skip, param.status), + unique_ (unique) + { + bind_param (param.bind, param.count); + } + + delete_statement:: + delete_statement (connection_type& conn, + const char* text, + binding& param, + bool copy_text) + : bulk_statement (conn, + text, statement_delete, + 0, false, + param.batch, param.skip, param.status, + copy_text), + unique_ (false) + { + assert (param.batch == 1); // Specify unique_hint explicitly. + bind_param (param.bind, param.count); + } + + delete_statement:: + delete_statement (connection_type& conn, + const char* text, + bool unique, + binding& param, + bool copy_text) + : bulk_statement (conn, + text, statement_delete, + 0, false, + param.batch, param.skip, param.status, + copy_text), + unique_ (unique) + { + bind_param (param.bind, param.count); + } + + size_t delete_statement:: + execute (size_t n, multiple_exceptions* mex) + { + // In batch DELETE without the OUTPUT clause (which is the + // only kind we currently support) all the parameter sets + // are processed inside SQLExecute() and the total count of + // affected rows is available after it returns. + // + + SQLRETURN r (bulk_statement::execute (n, mex)); + + // Statement failed as a whole, assume no parameter sets were + // attempted in case of a batch. + // + if (!(SQL_SUCCEEDED (r) || r == SQL_NO_DATA)) + { + translate_error (r, conn_, stmt_, 0, mex_); + return n_; + } + + // Extract error information for failed parameter sets. If we do + // this after calling SQLRowCount(), all the diagnostics records + // that we need will be gone. + // + size_t errors (status_ != 0 ? extract_errors () : 0); + + // Figure out the affected row count. + // + result_ = affected (r, errors, unique_); + + return n_; + } + } +} diff --git a/libodb-mssql/odb/mssql/statement.hxx b/libodb-mssql/odb/mssql/statement.hxx new file mode 100644 index 0000000..74326a0 --- /dev/null +++ b/libodb-mssql/odb/mssql/statement.hxx @@ -0,0 +1,558 @@ +// file : odb/mssql/statement.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_STATEMENT_HXX +#define ODB_MSSQL_STATEMENT_HXX + +#include + +#include +#include // std::size_t + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class connection; + + class LIBODB_MSSQL_EXPORT statement: public odb::statement + { + public: + typedef mssql::connection connection_type; + + virtual + ~statement () = 0; + + SQLHSTMT + handle () const + { + return stmt_; + } + + virtual const char* + text () const; + + virtual connection_type& + connection () + { + return conn_; + } + + // A statement can be empty. This is used to handle situations + // where a SELECT or UPDATE statement ends up not having any + // columns after processing. An empty statement cannot be + // executed. + // + bool + empty () const + { + return stmt_ == 0; + } + + protected: + // We keep two versions to take advantage of std::string COW. + // + statement (connection_type&, + const std::string& text, + statement_kind, + const binding* process, + bool optimize); + + statement (connection_type&, + const char* text, + statement_kind, + const binding* process, + bool optimize, + bool copy_text); + + private: + void + init (std::size_t text_size, + statement_kind, + const binding* process, + bool optimize); + + // Custom implementation for SQL Server that also moves long data + // columns to the end. + // + static void + process_select (std::string& result, + const char* statement, + const bind*, + std::size_t bind_size, + bool optimize); + + protected: + void + bind_param (bind*, std::size_t count); + + // Return the actual number of columns bound. + // + SQLUSMALLINT + bind_result (bind*, std::size_t count, SQLUSMALLINT& long_count); + + SQLRETURN + execute (); + + // The old_base and new_base arguments can be used to "re-base" + // the long_callback struct pointer (stored in bind::buffer). + // This is used by the query machinery to cause stream_result() + // to use the callback information from a copy of the image + // instead of the bound image. + // + void + stream_result (SQLUSMALLINT start_col, + bind*, + std::size_t count, + void* old_base = 0, + void* new_base = 0); + + protected: + connection_type& conn_; + std::string text_copy_; + const char* text_; + auto_handle stmt_; + }; + + class LIBODB_MSSQL_EXPORT bulk_statement: public statement + { + public: + virtual + ~bulk_statement () = 0; + + protected: + bulk_statement (connection_type&, + const std::string& text, + statement_kind, + const binding* process, + bool optimize, + std::size_t batch, + std::size_t skip, + SQLUSMALLINT* status); + + bulk_statement (connection_type&, + const char* text, + statement_kind, + const binding* process, + bool optimize, + std::size_t batch, + std::size_t skip, + SQLUSMALLINT* status, + bool copy_text); + + // Call SQLExecute() and set up the batch tracking variables (see + // below). Note that this function does not treat SQL_NO_DATA as + // an error since for DELETE and UPDATE statements this is a + // shortcut notation for zero rows affected. + // + SQLRETURN + execute (std::size_t n, multiple_exceptions*); + + // Return the number of failed parameter sets. + // + std::size_t + extract_errors (); + + static const unsigned long long result_unknown = ~0ULL; + + unsigned long long + affected (SQLRETURN, std::size_t errors, bool unique); + + private: + void + init (std::size_t skip); + + protected: + SQLULEN processed_; // Number of parameter sets processed so far. + SQLUSMALLINT* status_; // Parameter sets status array. + std::size_t n_; // Actual batch size. + std::size_t i_; // Position in result. + multiple_exceptions* mex_; + }; + + class LIBODB_MSSQL_EXPORT select_statement: public statement + { + public: + virtual + ~select_statement (); + + // While the long data columns can appear in any order in the + // result binding, they should appear last in the statement + // text. + // + select_statement (connection_type& conn, + const std::string& text, + bool process_text, + bool optimize_text, + binding& param, + binding& result); + + select_statement (connection_type& conn, + const char* text, + bool process_text, + bool optimize_text, + binding& param, + binding& result, + bool copy_text = true); + + select_statement (connection_type& conn, + const std::string& text, + bool process_text, + bool optimize_text, + binding& result); + + select_statement (connection_type& conn, + const char* text, + bool process_text, + bool optimize_text, + binding& result, + bool copy_text = true); + + enum result + { + success, + no_data + }; + + void + execute (); + + result + fetch (); + + // Return true if any long data was streamed. + // + bool + stream_result (void* old_base = 0, void* new_base = 0) + { + if (long_count_ != 0) + statement::stream_result (result_count_, + result_.bind, + result_.count, + old_base, + new_base); + return long_count_ != 0; + } + + void + free_result (); + + private: + select_statement (const select_statement&); + select_statement& operator= (const select_statement&); + + private: + binding& result_; + SQLUSMALLINT result_count_; // Actual number of columns bound. + SQLUSMALLINT long_count_; // Number of long data columns. + SQLUSMALLINT columns_; // Number of columns in result set. + }; + + struct LIBODB_MSSQL_EXPORT auto_result + { + explicit auto_result (select_statement& s): s_ (&s) {} + ~auto_result () {free ();} + + // Extended interface to support delayed freeing. + // + auto_result (): s_ (0) {} + + void + set (select_statement& s) {s_ = &s;} + + void + free () + { + if (s_ != 0) + { + s_->free_result (); + s_ = 0; + } + } + + void + release () {s_ = 0;} + + private: + auto_result (const auto_result&); + auto_result& operator= (const auto_result&); + + private: + select_statement* s_; + }; + + class LIBODB_MSSQL_EXPORT insert_statement: public bulk_statement + { + public: + virtual + ~insert_statement (); + + insert_statement (connection_type& conn, + const std::string& text, + bool process_text, + binding& param, + bool returning_id, + bool returning_version, + binding* returning); + + insert_statement (connection_type& conn, + const char* text, + bool process_text, + binding& param, + bool returning_id, + bool returning_version, + binding* returning, + bool copy_text = true); + + // Return the number of parameter sets (out of n) that were attempted. + // + std::size_t + execute (std::size_t n, multiple_exceptions& mex) + { + return execute (n, &mex); + } + + // Return true if successful and false if this row is a duplicate. + // All other errors are reported by throwing exceptions. + // + bool + result (std::size_t i); + + bool + execute () + { + execute (1, 0); + return result (0); + } + + private: + insert_statement (const insert_statement&); + insert_statement& operator= (const insert_statement&); + + private: + void + init_result (); + + std::size_t + execute (std::size_t, multiple_exceptions*); + + void + fetch (SQLRETURN); + + private: + bool returning_id_; + bool returning_version_; + binding* ret_; + bool text_batch_; + + bool result_; + }; + + class LIBODB_MSSQL_EXPORT update_statement: public bulk_statement + { + public: + virtual + ~update_statement (); + + // SQL Server native client ODBC driver does not expose individual + // affected row counts for batch operations, even though it says it + // does (SQLGetInfo(SQL_PARAM_ARRAY_ROW_COUNTS) returns SQL_PARC_BATCH). + // Instead, it adds them all up and returns a single count. This is + // bad news for us. + // + // In case of updating by primary key (the affected row count is + // either 1 or 0), we can recognize the presumably successful case + // where the total affected row count is equal to the batch size + // (we can also recognize the "all unsuccessful" case where the + // total affected row count is 0). The unique_hint argument in the + // constructors below indicates whether this is a "0 or 1" UPDATE + // statement. + // + // In all other situations (provided this is a batch), the result() + // function below returns the special result_unknown value. + // + update_statement (connection_type& conn, + const std::string& text, + bool process, + binding& param, + binding* returning); + + update_statement (connection_type& conn, + const std::string& text, + bool unique_hint, + bool process, + binding& param, + binding* returning); + + update_statement (connection_type& conn, + const char* text, + bool process, + binding& param, + binding* returning, + bool copy_text = true); + + update_statement (connection_type& conn, + const char* text, + bool unique_hint, + bool process, + binding& param, + binding* returning, + bool copy_text = true); + + // Return the number of parameter sets (out of n) that were attempted. + // + std::size_t + execute (std::size_t n, multiple_exceptions& mex) + { + return execute (n, &mex); + } + + // Return the number of rows affected (updated) by the parameter + // set. If this is a batch (n > 1 in execute() call above) and it + // is impossible to determine the affected row count for each + // parameter set, then this function returns result_unknown. All + // other errors are reported by throwing exceptions. + // + using bulk_statement::result_unknown; + + unsigned long long + result (std::size_t i) + { + if (i != i_) + mex_->current (++i_); // mex cannot be NULL since this is a batch. + + return result_; + } + + unsigned long long + execute () + { + execute (1, 0); + return result (0); + } + + private: + update_statement (const update_statement&); + update_statement& operator= (const update_statement&); + + private: + void + init (binding& param, binding* ret); + + std::size_t + execute (std::size_t, multiple_exceptions*); + + private: + bool unique_; + bool returning_; + + unsigned long long result_; + }; + + class LIBODB_MSSQL_EXPORT delete_statement: public bulk_statement + { + public: + virtual + ~delete_statement (); + + // SQL Server native client ODBC driver does not expose individual + // affected row counts for batch operations, even though it says it + // does (SQLGetInfo(SQL_PARAM_ARRAY_ROW_COUNTS) returns SQL_PARC_BATCH). + // Instead, it adds them all up and returns a single count. This is + // bad news for us. + // + // In case of deleting by primary key (the affected row count is + // either 1 or 0), we can recognize the presumably successful case + // where the total affected row count is equal to the batch size + // (we can also recognize the "all unsuccessful" case where the + // total affected row count is 0). The unique_hint argument in the + // constructors below indicates whether this is a "0 or 1" DELETE + // statement. + // + // In all other situations (provided this is a batch), the result() + // function below returns the special result_unknown value. + // + delete_statement (connection_type& conn, + const std::string& text, + binding& param); + + delete_statement (connection_type& conn, + const std::string& text, + bool unique_hint, + binding& param); + + delete_statement (connection_type& conn, + const char* text, + binding& param, + bool copy_text = true); + + delete_statement (connection_type& conn, + const char* text, + bool unique_hint, + binding& param, + bool copy_text = true); + + // Return the number of parameter sets (out of n) that were attempted. + // + std::size_t + execute (std::size_t n, multiple_exceptions& mex) + { + return execute (n, &mex); + } + + // Return the number of rows affected (deleted) by the parameter + // set. If this is a batch (n > 1 in execute() call above) and it + // is impossible to determine the affected row count for each + // parameter set, then this function returns result_unknown. All + // other errors are reported by throwing exceptions. + // + using bulk_statement::result_unknown; + + unsigned long long + result (std::size_t i) + { + if (i != i_) + mex_->current (++i_); // mex cannot be NULL since this is a batch. + + return result_; + } + + unsigned long long + execute () + { + execute (1, 0); + return result (0); + } + + private: + delete_statement (const delete_statement&); + delete_statement& operator= (const delete_statement&); + + private: + std::size_t + execute (std::size_t, multiple_exceptions*); + + private: + bool unique_; + unsigned long long result_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_STATEMENT_HXX diff --git a/libodb-mssql/odb/mssql/statement.ixx b/libodb-mssql/odb/mssql/statement.ixx new file mode 100644 index 0000000..12cce80 --- /dev/null +++ b/libodb-mssql/odb/mssql/statement.ixx @@ -0,0 +1,41 @@ +// file : odb/mssql/statement.ixx +// license : ODB NCUEL; see accompanying LICENSE file + +namespace odb +{ + namespace mssql + { + inline bulk_statement:: + bulk_statement (connection_type& c, + const std::string& text, + statement_kind k, + const binding* process, + bool optimize, + std::size_t batch, + std::size_t skip, + SQLUSMALLINT* status) + : statement (c, text, k, process, optimize), + status_ (batch == 1 ? 0 : status) + { + if (status_ != 0 && !empty ()) + init (skip); + } + + inline bulk_statement:: + bulk_statement (connection_type& c, + const char* text, + statement_kind k, + const binding* process, + bool optimize, + std::size_t batch, + std::size_t skip, + SQLUSMALLINT* status, + bool copy_text) + : statement (c, text, k, process, optimize, copy_text), + status_ (batch == 1 ? 0 : status) + { + if (status_ != 0 && !empty ()) + init (skip); + } + } +} diff --git a/libodb-mssql/odb/mssql/statements-base.cxx b/libodb-mssql/odb/mssql/statements-base.cxx new file mode 100644 index 0000000..9f302e3 --- /dev/null +++ b/libodb-mssql/odb/mssql/statements-base.cxx @@ -0,0 +1,15 @@ +// file : odb/mssql/statements-base.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +namespace odb +{ + namespace mssql + { + statements_base:: + ~statements_base () + { + } + } +} diff --git a/libodb-mssql/odb/mssql/statements-base.hxx b/libodb-mssql/odb/mssql/statements-base.hxx new file mode 100644 index 0000000..4506628 --- /dev/null +++ b/libodb-mssql/odb/mssql/statements-base.hxx @@ -0,0 +1,63 @@ +// file : odb/mssql/statements-base.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_STATEMENTS_BASE_HXX +#define ODB_MSSQL_STATEMENTS_BASE_HXX + +#include + +#include +#include + +#include +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class LIBODB_MSSQL_EXPORT statements_base: public details::shared_base + { + public: + typedef mssql::connection connection_type; + + connection_type& + connection () + { + return conn_; + } + + // Schema version. database::schema_version_migration() is thread- + // safe which means it is also slow. Cache the result in statements + // so we can avoid the mutex lock. This is thread-safe since if the + // version is updated, then the statements cache will be expired. + // + const schema_version_migration& + version_migration (const char* name = "") const + { + if (svm_ == 0) + svm_ = &conn_.database ().schema_version_migration (name); + + return *svm_; + } + + public: + virtual + ~statements_base (); + + protected: + statements_base (connection_type& conn): conn_ (conn), svm_ (0) {} + + protected: + connection_type& conn_; + mutable const schema_version_migration* svm_; + }; + } +} + +#include + +#endif // ODB_MSSQL_STATEMENTS_BASE_HXX diff --git a/libodb-mssql/odb/mssql/tracer.cxx b/libodb-mssql/odb/mssql/tracer.cxx new file mode 100644 index 0000000..3fe62c9 --- /dev/null +++ b/libodb-mssql/odb/mssql/tracer.cxx @@ -0,0 +1,60 @@ +// file : odb/mssql/tracer.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include +#include +#include + +namespace odb +{ + namespace mssql + { + tracer:: + ~tracer () + { + } + + void tracer:: + prepare (connection&, const statement&) + { + } + + void tracer:: + execute (connection& c, const statement& s) + { + execute (c, s.text ()); + } + + void tracer:: + deallocate (connection&, const statement&) + { + } + + void tracer:: + prepare (odb::connection& c, const odb::statement& s) + { + prepare (static_cast (c), + static_cast (s)); + } + + void tracer:: + execute (odb::connection& c, const odb::statement& s) + { + execute (static_cast (c), + static_cast (s)); + } + + void tracer:: + execute (odb::connection& c, const char* s) + { + execute (static_cast (c), s); + } + + void tracer:: + deallocate (odb::connection& c, const odb::statement& s) + { + deallocate (static_cast (c), + static_cast (s)); + } + } +} diff --git a/libodb-mssql/odb/mssql/tracer.hxx b/libodb-mssql/odb/mssql/tracer.hxx new file mode 100644 index 0000000..feaf5f0 --- /dev/null +++ b/libodb-mssql/odb/mssql/tracer.hxx @@ -0,0 +1,61 @@ +// file : odb/mssql/tracer.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_TRACER_HXX +#define ODB_MSSQL_TRACER_HXX + +#include + +#include + +#include +#include +#include + +namespace odb +{ + namespace mssql + { + class LIBODB_MSSQL_EXPORT tracer: private odb::tracer + { + public: + virtual + ~tracer (); + + virtual void + prepare (connection&, const statement&); + + virtual void + execute (connection&, const statement&); + + virtual void + execute (connection&, const char* statement) = 0; + + virtual void + deallocate (connection&, const statement&); + + private: + // Allow these classes to convert mssql::tracer to odb::tracer. + // + friend class database; + friend class connection; + friend class transaction; + + virtual void + prepare (odb::connection&, const odb::statement&); + + virtual void + execute (odb::connection&, const odb::statement&); + + virtual void + execute (odb::connection&, const char* statement); + + virtual void + deallocate (odb::connection&, const odb::statement&); + }; + } +} + +#include + +#endif // ODB_MSSQL_TRACER_HXX diff --git a/libodb-mssql/odb/mssql/traits-calls.hxx b/libodb-mssql/odb/mssql/traits-calls.hxx new file mode 100644 index 0000000..6b20dbd --- /dev/null +++ b/libodb-mssql/odb/mssql/traits-calls.hxx @@ -0,0 +1,190 @@ +// file : odb/mssql/traits-calls.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_TRAITS_CALLS_HXX +#define ODB_MSSQL_TRAITS_CALLS_HXX + +#include + +#include // std::size_t + +#include +#include +#include + +#include +#include + +namespace odb +{ + namespace mssql + { + // + // object_traits_calls + // + + template ::versioned> + struct object_traits_calls; + + template + struct object_traits_calls + { + typedef object_traits_impl traits; + typedef typename traits::image_type image_type; + typedef mssql::bind bind_type; + + object_traits_calls (const schema_version_migration*) {} + + const schema_version_migration* + version () const {return 0;} + + static void + bind (bind_type* b, image_type& i, statement_kind sk) + { + traits::bind (b, i, sk); + } + + // Poly-derived version. + // + static void + bind (bind_type* b, + const bind_type* id, std::size_t id_size, + image_type& i, + statement_kind sk) + { + traits::bind (b, id, id_size, i, sk); + } + + static void + init (T& o, const image_type& i, odb::database* db) + { + traits::init (o, i, db); + } + + static bool + find_ (typename traits::statements_type& sts, + const typename traits::id_type* id) + { + return traits::find_ (sts, id); + } + + static void + load_ (typename traits::statements_type& sts, T& o, bool reload) + { + return traits::load_ (sts, o, reload); + } + }; + + template + struct object_traits_calls + { + typedef object_traits_impl traits; + typedef typename traits::image_type image_type; + typedef mssql::bind bind_type; + + object_traits_calls (const schema_version_migration* svm): svm_ (*svm) {} + + const schema_version_migration* + version () const {return &svm_;} + + void + bind (bind_type* b, image_type& i, statement_kind sk) const + { + traits::bind (b, i, sk, svm_); + } + + // Poly-derived version. + // + void + bind (bind_type* b, + const bind_type* id, std::size_t id_size, + image_type& i, + statement_kind sk) const + { + traits::bind (b, id, id_size, i, sk, svm_); + } + + void + init (T& o, const image_type& i, odb::database* db) const + { + traits::init (o, i, db, svm_); + } + + bool + find_ (typename traits::statements_type& sts, + const typename traits::id_type* id) const + { + return traits::find_ (sts, id, svm_); + } + + void + load_ (typename traits::statements_type& sts, T& o, bool reload) const + { + return traits::load_ (sts, o, reload, svm_); + } + + private: + const schema_version_migration& svm_; + }; + + // + // view_traits_calls + // + + template ::versioned> + struct view_traits_calls; + + template + struct view_traits_calls + { + typedef view_traits_impl traits; + typedef typename traits::image_type image_type; + typedef mssql::bind bind_type; + + view_traits_calls (const schema_version_migration*) {} + + static void + bind (bind_type* b, image_type& i) + { + traits::bind (b, i); + } + + static void + init (T& o, const image_type& i, odb::database* db) + { + traits::init (o, i, db); + } + }; + + template + struct view_traits_calls + { + typedef view_traits_impl traits; + typedef typename traits::image_type image_type; + typedef mssql::bind bind_type; + + view_traits_calls (const schema_version_migration* svm): svm_ (*svm) {} + + void + bind (bind_type* b, image_type& i) const + { + traits::bind (b, i, svm_); + } + + void + init (T& o, const image_type& i, odb::database* db) const + { + traits::init (o, i, db, svm_); + } + + private: + const schema_version_migration& svm_; + }; + } +} + +#include + +#endif // ODB_MSSQL_TRAITS_CALLS_HXX diff --git a/libodb-mssql/odb/mssql/traits.cxx b/libodb-mssql/odb/mssql/traits.cxx new file mode 100644 index 0000000..9a9d4fa --- /dev/null +++ b/libodb-mssql/odb/mssql/traits.cxx @@ -0,0 +1,616 @@ +// file : odb/mssql/traits.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +#include + +using namespace std; + +namespace odb +{ + namespace mssql + { + // + // c_array_value_traits_base + // + void c_array_value_traits_base:: + set_value (char* const& v, + const char* b, + size_t n, + bool is_null, + size_t N) + { + if (!is_null) + { + n = n < N ? n : N; + + if (n != 0) + memcpy (v, b, n); + } + else + n = 0; + + if (n != N) // Append '\0' if there is space. + v[n] = '\0'; + } + + void c_array_value_traits_base:: + set_image (char* b, + size_t c, + size_t& n, + bool& is_null, + const char* v, + size_t N) + { + is_null = false; + + // Figure out the length. We cannot use strlen since it may + // not be 0-terminated (strnlen is not standard). + // + for (n = 0; n != N && v[n] != '\0'; ++n) ; + + if (n > c) + n = c; + + if (n != 0) + memcpy (b, v, n); + } + + // + // default_value_traits + // + void default_value_traits:: + param_callback (const void* context, + size_t*, + const void** buffer, + size_t* size, + chunk_type* chunk, + void*, + size_t) + { + const string& str (*static_cast (context)); + + *buffer = str.c_str (); + *size = str.size (); + *chunk = chunk_one; + } + + void default_value_traits:: + result_callback (void* context, + size_t* position, + void** buffer, + size_t* size, + chunk_type chunk, + size_t size_left, + void* tmp_buf, + size_t tmp_capacity) + { + string& str (*static_cast (context)); + + switch (chunk) + { + case chunk_null: + case chunk_one: + { + str.clear (); + break; + } + case chunk_first: + { + // If the total size is available, then pre-allocate the string + // and copy the data directly into its buffer in one go. While + // this kind of direct modification of the std::string buffer + // is not sanctioned by the standard, this is known to work + // with all the implementations we care to support. We just + // need to make sure the underlying buffer is not shared with + // any other instance if the implementation uses COW. + // + if (size_left != 0) + { + size_left++; // One extra for the null terminator. + + if (str.size () != size_left) + str.resize (size_left); + else + str[0] = '\0'; // Force copy in a COW implementation. + + *buffer = const_cast (str.c_str ()); + *size = size_left; + *position = 0; // Indicator. + } + else + { + // If the total size is not available, do the short string + // optimization by first returning a small temporary buffer. + // If the data fits, then we copy it over to the string and + // thus get the precise buffer allocation. If the data does + // not fit, then we resort to the exponential buffer growth. + // + *buffer = tmp_buf; + *size = tmp_capacity > 128 ? 128 : tmp_capacity; + *position = 1; // Indicator. + } + + break; + } + case chunk_next: + { + // We should only end up here if the short string optimization + // didn't work out. + // + assert (*position != 0); + + if (*position == 1) + { + // First chunk_next call. There is some data in the temp + // buffer which we need to copy over. + // + str.reserve (256); + str.assign (static_cast (tmp_buf), *size); + *position = *size; // Size of actual data in str, which got to be + // greater than 128, or we would have gotten + // chunk_last. + str.resize (256); + } + else + { + // Subsequent chunk_next call. Double the buffer and continue. + // + *position += *size; + str.resize (str.size () * 2); + } + + *buffer = const_cast (str.c_str ()) + *position; + *size = str.size () - *position; + break; + } + case chunk_last: + { + if (*position == 0) + str.resize (*size); + else if (*position == 1) + // Short string optimization worked out. There is some data + // in the temp buffer which we need to copy over. + // + str.assign (static_cast (tmp_buf), *size); + else + str.resize (*position + *size); + + break; + } + } + } + + // + // c_long_string_value_traits + // + void c_string_long_value_traits:: + param_callback (const void* context, + size_t*, + const void** buffer, + size_t* size, + chunk_type* chunk, + void*, + size_t) + { + *buffer = context; + *size = strlen (static_cast (context)); + *chunk = chunk_one; + } + + // + // c_warray_value_traits_base + // + void c_warray_value_traits_base:: + set_value (wchar_t* const& v, + const ucs2_char* b, + size_t n, + bool is_null, + size_t N) + { + if (!is_null) + { + n = n < N ? n : N; + + if (n != 0) + functions::assign (v, b, n); + } + else + n = 0; + + if (n != N) // Append '\0' if there is space. + v[n] = L'\0'; + } + + void c_warray_value_traits_base:: + set_image (ucs2_char* b, + size_t c, + size_t& n, + bool& is_null, + const wchar_t* v, + size_t N) + { + is_null = false; + + // Figure out the length. We cannot use wcslen since it may + // not be 0-terminated (wcsnlen is not standard). + // + for (n = 0; n != N && v[n] != L'\0'; ++n) ; + + if (n > c) + n = c; + + if (n != 0) + functions::assign (b, v, n); + } + + // + // wstring_long_value_traits<2> + // + void wstring_long_value_traits<2>:: + param_callback (const void* context, + size_t*, + const void** buffer, + size_t* size, + chunk_type* chunk, + void*, + size_t) + { + const wstring& str (*static_cast (context)); + + *buffer = str.c_str (); + *size = str.size () * 2; // In bytes. + *chunk = chunk_one; + } + + void wstring_long_value_traits<2>:: + result_callback (void* context, + size_t*, + void** buffer, + size_t* size, + chunk_type chunk, + size_t size_left, + void*, + size_t) + { + wstring& str (*static_cast (context)); + + switch (chunk) + { + case chunk_null: + case chunk_one: + { + str.clear (); + break; + } + case chunk_first: + { + // The Native Client ODBC driver seems to always be able to + // return the total size for national character strings. This + // makes things simple and efficient. + // + assert (size_left != 0); + + size_left /= 2; // Convert to characters. + size_left++; // One extra for the null terminator. + + if (str.size () != size_left) + str.resize (size_left); + else + str[0] = L'\0'; // Force copy in a COW implementation. + + *buffer = const_cast (str.c_str ()); + *size = size_left * 2; // In bytes. + break; + } + case chunk_next: + { + // We should never get here. + // + assert (false); + break; + } + case chunk_last: + { + str.resize (*size / 2); // Get rid of the null terminator. + break; + } + } + } + + // + // wstring_long_value_traits<4> + // +#ifndef _WIN32 + void wstring_long_value_traits<4>:: + param_callback (const void* context, + size_t* position, + const void** buffer, + size_t* size, + chunk_type* chunk, + void* tmp_buf, + size_t tmp_capacity) + { + const wstring& str (*static_cast (context)); + + // Here we cannot just return the pointer to the underlying buffer + // since the character sizes are different. Instead we copy the + // data to the temporary buffer. + // + *buffer = tmp_buf; + *size = str.size () - *position; // In UCS-2 characters. + + if (*size > tmp_capacity / 2) + { + *size = tmp_capacity / 2; + *chunk = chunk_next; + } + else + *chunk = chunk_last; + + wstring_functions<>::assign (static_cast (tmp_buf), + str.c_str () + *position, + *size); + if (*position == 0) + { + if (*chunk == chunk_last) + *chunk = chunk_one; + else + *chunk = chunk_first; + } + + *position += *size; + *size *= 2; // Convert to bytes. + } + + void wstring_long_value_traits<4>:: + result_callback (void* context, + size_t*, + void** buffer, + size_t* size, + chunk_type chunk, + size_t size_left, + void* tmp_buf, + size_t tmp_capacity) + { + wstring& str (*static_cast (context)); + + // Again, we cannot do direct buffer copy and have to use the + // temporary buffer instead. + // + switch (chunk) + { + case chunk_null: + case chunk_one: + { + str.clear (); + break; + } + case chunk_first: + { + // The Native Client ODBC driver seems to always be able to + // return the total size for national character strings. Use + // this to reserve enough space in the string. + // + assert (size_left != 0); + str.reserve (size_left / 2); + break; + } + case chunk_next: + case chunk_last: + { + // Append the data from the temporary buffer. + // + ucs2_char* p (static_cast (tmp_buf)); + str.append (p, p + *size / 2); + break; + } + } + + if (chunk == chunk_first || chunk == chunk_next) + { + *buffer = tmp_buf; + *size = tmp_capacity; + } + } +#endif // _WIN32 + + // + // c_wstring_long_value_traits<2> + // + void c_wstring_long_value_traits<2>:: + param_callback (const void* context, + size_t*, + const void** buffer, + size_t* size, + chunk_type* chunk, + void*, + size_t) + { + *buffer = context; + *size = wcslen (static_cast (context)) * 2; // In bytes. + *chunk = chunk_one; + } + + // + // c_wstring_long_value_traits<4> + // +#ifndef _WIN32 + void c_wstring_long_value_traits<4>:: + param_callback (const void* context, + size_t* position, + const void** buffer, + size_t* size, + chunk_type* chunk, + void* tmp_buf, + size_t tmp_capacity) + { + const wchar_t* str (static_cast (context)); + + // Here we cannot just return the pointer to the buffer since the + // character sizes are different. Instead we copy the data to the + // temporary buffer. + // + *buffer = tmp_buf; + *size = wcslen (str) - *position; // In UCS-2 characters. + + if (*size > tmp_capacity / 2) + { + *size = tmp_capacity / 2; + *chunk = chunk_next; + } + else + *chunk = chunk_last; + + wstring_functions<>::assign (static_cast (tmp_buf), + str + *position, + *size); + if (*position == 0) + { + if (*chunk == chunk_last) + *chunk = chunk_one; + else + *chunk = chunk_first; + } + + *position += *size; + *size *= 2; // Convert to bytes. + } +#endif // _WIN32 + + // + // default_value_traits, id_long_binary> + // + // std::vector has to be qualified for Sun CC. + // + void default_value_traits, id_long_binary>:: + param_callback (const void* context, + size_t*, + const void** buffer, + size_t* size, + chunk_type* chunk, + void*, + size_t) + { + const value_type& v (*static_cast (context)); + + *buffer = v.empty () ? 0 : &v.front (); + *size = v.size (); + *chunk = chunk_one; + } + + void default_value_traits, id_long_binary>:: + result_callback (void* context, + size_t*, + void** buffer, + size_t* size, + chunk_type chunk, + size_t size_left, + void*, + size_t) + { + value_type& v (*static_cast (context)); + + switch (chunk) + { + case chunk_null: + case chunk_one: + { + v.clear (); + break; + } + case chunk_first: + { + // The Native Client ODBC driver seems to always be able to + // return the total size. This makes things simple and + // efficient. + // + assert (size_left != 0); + + v.resize (size_left); + *buffer = &v.front (); + *size = size_left; + break; + } + case chunk_next: + { + // We should never get here. + // + assert (false); + break; + } + case chunk_last: + { + // Nothing to do here. The vector is already of the correct size + // and should contain the data. + break; + } + } + } + + // + // default_value_traits, id_long_binary> + // + // std::vector has to be qualified for Sun CC. + // + void default_value_traits, id_long_binary>:: + param_callback (const void* context, + size_t*, + const void** buffer, + size_t* size, + chunk_type* chunk, + void*, + size_t) + { + const value_type& v (*static_cast (context)); + + *buffer = v.empty () ? 0 : &v.front (); + *size = v.size (); + *chunk = chunk_one; + } + + void default_value_traits, id_long_binary>:: + result_callback (void* context, + size_t*, + void** buffer, + size_t* size, + chunk_type chunk, + size_t size_left, + void*, + size_t) + { + // The code is exactly the same as in the vector specialization. + // + value_type& v (*static_cast (context)); + + switch (chunk) + { + case chunk_null: + case chunk_one: + { + v.clear (); + break; + } + case chunk_first: + { + assert (size_left != 0); + + v.resize (size_left); + *buffer = &v.front (); + *size = size_left; + break; + } + case chunk_next: + { + assert (false); + break; + } + case chunk_last: + { + break; + } + } + } + } +} diff --git a/libodb-mssql/odb/mssql/traits.hxx b/libodb-mssql/odb/mssql/traits.hxx new file mode 100644 index 0000000..f53e535 --- /dev/null +++ b/libodb-mssql/odb/mssql/traits.hxx @@ -0,0 +1,2176 @@ +// file : odb/mssql/traits.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_TRAITS_HXX +#define ODB_MSSQL_TRAITS_HXX + +#include + +#include // ODB_CXX11 + +#include +#include +#include // std::size_t +#include // std::memcpy, std::memset, std::strlen +#include // std::wcslen + +#ifdef ODB_CXX11 +# include +#endif + +#ifdef _WIN32 +typedef struct _GUID GUID; +#endif + +#include +#include + +#include +#include + +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + enum database_type_id + { + id_bit, + id_tinyint, + id_smallint, + id_int, + id_bigint, + + id_decimal, // DECIMAL; NUMERIC + + id_smallmoney, + id_money, + + id_float4, // REAL; FLOAT(n) with n <= 24 + id_float8, // FLOAT(n) with n > 24 + + id_string, // CHAR(n), VARCHAR(n) with n <= N + id_long_string, // CHAR(n), VARCHAR(n) with n > N; TEXT + + id_nstring, // NCHAR(n), NVARCHAR(n) with 2*n <= N + id_long_nstring, // NCHAR(n), NVARCHAR(n) with 2*n > N; NTEXT + + id_binary, // BINARY(n), VARBINARY(n) with n <= N + id_long_binary, // BINARY(n), VARBINARY(n) with n > N; IMAGE + + id_date, // DATE + id_time, // TIME + id_datetime, // DATETIME; DATETIME2; SMALLDATETIME + id_datetimeoffset, // DATETIMEOFFSET + + id_uniqueidentifier, // UNIQUEIDENTIFIER + id_rowversion // ROWVERSION; TIMESTAMP + }; + + // + // image_traits + // + + template + struct image_traits; + + template <> + struct image_traits {typedef unsigned char image_type;}; + + template <> + struct image_traits {typedef unsigned char image_type;}; + + template <> + struct image_traits {typedef short image_type;}; + + template <> + struct image_traits {typedef int image_type;}; + + template <> + struct image_traits {typedef long long image_type;}; + + template <> + struct image_traits {typedef decimal image_type;}; + + template <> + struct image_traits {typedef smallmoney image_type;}; + + template <> + struct image_traits {typedef money image_type;}; + + template <> + struct image_traits {typedef float image_type;}; + + template <> + struct image_traits {typedef double image_type;}; + + template <> + struct image_traits {typedef char* image_type;}; + + template <> + struct image_traits {typedef long_callback image_type;}; + + template <> + struct image_traits {typedef ucs2_char* image_type;}; + + template <> + struct image_traits {typedef long_callback image_type;}; + + template <> + struct image_traits {typedef char* image_type;}; + + template <> + struct image_traits {typedef long_callback image_type;}; + + template <> + struct image_traits {typedef date image_type;}; + + template <> + struct image_traits {typedef time image_type;}; + + template <> + struct image_traits {typedef datetime image_type;}; + + template <> + struct image_traits + { + typedef datetimeoffset image_type; + }; + + template <> + struct image_traits + { + typedef uniqueidentifier image_type; + }; + + // Image is an 8-byte sequence. + // + template <> + struct image_traits {typedef unsigned char* image_type;}; + + // + // value_traits + // + + template + struct wrapped_value_traits; + + template + struct default_value_traits; + + template ::r> + struct select_traits; + + template + struct select_traits + { + typedef default_value_traits type; + }; + + template + struct select_traits + { + typedef + wrapped_value_traits::null_handler> + type; + }; + + template + class value_traits: public select_traits::type + { + }; + + // The wrapped_value_traits specializations should be able to handle + // any value type which means we have to have every possible signature + // of the set_value() and set_image() functions. + // + template + struct wrapped_value_traits + { + typedef wrapper_traits wtraits; + typedef typename wtraits::unrestricted_wrapped_type wrapped_type; + + typedef W value_type; + typedef wrapped_type query_type; + typedef typename image_traits::image_type image_type; + + typedef value_traits vtraits; + + static void + set_value (W& v, const image_type& i, bool is_null) + { + vtraits::set_value (wtraits::set_ref (v), i, is_null); + } + + static void + set_image (image_type& i, bool& is_null, const W& v) + { + vtraits::set_image (i, is_null, wtraits::get_ref (v)); + } + + // string, binary. + // + static void + set_value (W& v, const char* i, std::size_t n, bool is_null) + { + vtraits::set_value (wtraits::set_ref (v), i, n, is_null); + } + + static void + set_image (char* i, + std::size_t c, + std::size_t& n, + bool& is_null, + const W& v) + { + vtraits::set_image (i, c, n, is_null, wtraits::get_ref (v)); + } + + // nstring. + // + static void + set_value (W& v, const ucs2_char* i, std::size_t n, bool is_null) + { + vtraits::set_value (wtraits::set_ref (v), i, n, is_null); + } + + static void + set_image (ucs2_char* i, + std::size_t c, + std::size_t& n, + bool& is_null, + const W& v) + { + vtraits::set_image (i, c, n, is_null, wtraits::get_ref (v)); + } + + // long_string, long_nstring, long_binary. + // + static void + set_value (W& v, result_callback_type& cb, void*& context) + { + vtraits::set_value (wtraits::set_ref (v), cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const W& v) + { + vtraits::set_image (cb, context, is_null, wtraits::get_ref (v)); + } + + // time, datetime, datetimeoffset. + // + static void + set_image (image_type& i, unsigned short s, bool& is_null, const W& v) + { + vtraits::set_image (i, s, is_null, wtraits::get_ref (v)); + } + }; + + template + struct wrapped_value_traits + { + typedef wrapper_traits wtraits; + typedef typename wtraits::unrestricted_wrapped_type wrapped_type; + + typedef W value_type; + typedef wrapped_type query_type; + typedef typename image_traits::image_type image_type; + + typedef value_traits vtraits; + + static void + set_value (W& v, const image_type& i, bool is_null) + { + if (is_null) + wtraits::set_null (v); + else + vtraits::set_value (wtraits::set_ref (v), i, is_null); + } + + static void + set_image (image_type& i, bool& is_null, const W& v) + { + is_null = wtraits::get_null (v); + + if (!is_null) + vtraits::set_image (i, is_null, wtraits::get_ref (v)); + } + + // string, binary. + // + static void + set_value (W& v, const char* i, std::size_t n, bool is_null) + { + if (is_null) + wtraits::set_null (v); + else + vtraits::set_value (wtraits::set_ref (v), i, n, is_null); + } + + static void + set_image (char* i, + std::size_t c, + std::size_t& n, + bool& is_null, + const W& v) + { + is_null = wtraits::get_null (v); + + if (!is_null) + vtraits::set_image (i, c, n, is_null, wtraits::get_ref (v)); + } + + // nstring. + // + static void + set_value (W& v, const ucs2_char* i, std::size_t n, bool is_null) + { + if (is_null) + wtraits::set_null (v); + else + vtraits::set_value (wtraits::set_ref (v), i, n, is_null); + } + + static void + set_image (ucs2_char* i, + std::size_t c, + std::size_t& n, + bool& is_null, + const W& v) + { + is_null = wtraits::get_null (v); + + if (!is_null) + vtraits::set_image (i, c, n, is_null, wtraits::get_ref (v)); + } + + // long_string, long_nstring, long_binary. + // + static void + set_value (W& v, result_callback_type& cb, void*& context) + { + // We have to use our own callback since the NULL information + // is only available during streaming. + // + cb = &result_callback; + context = &v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const W& v) + { + is_null = wtraits::get_null (v); + + if (!is_null) + vtraits::set_image (cb, context, is_null, wtraits::get_ref (v)); + } + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); + + // time, datetime, datetimeoffset. + // + static void + set_image (image_type& i, unsigned short s, bool& is_null, const W& v) + { + is_null = wtraits::get_null (v); + + if (!is_null) + vtraits::set_image (i, s, is_null, wtraits::get_ref (v)); + } + }; + + template + struct default_value_traits + { + typedef T value_type; + typedef T query_type; + typedef typename image_traits::image_type image_type; + + static void + set_value (T& v, const image_type& i, bool is_null) + { + if (!is_null) + v = T (i); + else + v = T (); + } + + static void + set_image (image_type& i, bool& is_null, T v) + { + is_null = false; + i = image_type (v); + } + }; + + // smallmoney as float/double. + // + template + struct smallmoney_float_value_traits + { + typedef T value_type; + typedef T query_type; + typedef smallmoney image_type; + + static void + set_value (T& v, const smallmoney& i, bool is_null) + { + if (!is_null) + v = T (i.value / 10000) + T (i.value % 10000) / 10000; + else + v = T (); + } + + static void + set_image (smallmoney& i, bool& is_null, T v) + { + is_null = false; + i.value = static_cast (v) * 10000 + + static_cast (v * 10000) % 10000; + } + }; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits: + smallmoney_float_value_traits + { + }; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits: + smallmoney_float_value_traits + { + }; + + // smallmoney as integer. + // + template + struct default_value_traits + { + typedef T value_type; + typedef T query_type; + typedef smallmoney image_type; + + static void + set_value (T& v, const smallmoney& i, bool is_null) + { + if (!is_null) + v = static_cast (i.value); + else + v = T (); + } + + static void + set_image (smallmoney& i, bool& is_null, T v) + { + is_null = false; + i.value = static_cast (v); + } + }; + + // money as float/double. + // + template + struct money_float_value_traits + { + typedef T value_type; + typedef T query_type; + typedef money image_type; + + static void + set_value (T& v, const money& i, bool is_null) + { + if (!is_null) + { + long long iv ((static_cast (i.high) << 32) | i.low); + v = T (iv / 10000) + T (iv % 10000) / 10000; + } + else + v = T (); + } + + static void + set_image (money& i, bool& is_null, T v) + { + is_null = false; + long long iv (static_cast (v) * 10000 + + static_cast (v * 10000) % 10000); + i.high = static_cast (iv >> 32); + i.low = static_cast (iv); + } + }; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits: + money_float_value_traits + { + }; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits: + money_float_value_traits + { + }; + + // money as integer. + // + template + struct default_value_traits + { + typedef T value_type; + typedef T query_type; + typedef money image_type; + + static void + set_value (T& v, const money& i, bool is_null) + { + if (!is_null) + { + long long iv ((static_cast (i.high) << 32) | i.low); + v = static_cast (iv); + } + else + v = T (); + } + + static void + set_image (money& i, bool& is_null, T v) + { + is_null = false; + long long iv (static_cast (v)); + i.high = static_cast (iv >> 32); + i.low = static_cast (iv); + } + }; + + // std::string specialization for string. + // + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits + { + typedef std::string value_type; + typedef std::string query_type; + typedef char* image_type; + + static void + set_value (std::string& v, + const char* b, + std::size_t n, + bool is_null) + { + if (!is_null) + v.assign (b, n); + else + v.erase (); + } + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const std::string& v) + { + is_null = false; + n = v.size (); + + if (n > c) + n = c; + + if (n != 0) + std::memcpy (b, v.c_str (), n); + } + }; + + // char*/const char* specialization for string. + // + // Specialization for const char* which only supports initialization + // of an image from the value but not the other way around. This way + // we can pass such values to the queries. + // + class LIBODB_MSSQL_EXPORT c_string_value_traits + { + public: + typedef const char* value_type; + typedef char* image_type; + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const char* v) + { + is_null = false; + n = std::strlen (v); + + if (n > c) + n = c; + + if (n != 0) + std::memcpy (b, v, n); + } + }; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits: + c_string_value_traits {}; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits: + c_string_value_traits {}; + + // char[N] specialization. + // + struct LIBODB_MSSQL_EXPORT c_array_value_traits_base + { + static void + set_value (char* const& v, + const char* b, + std::size_t n, + bool is_null, + std::size_t N); + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const char* v, + std::size_t N); + }; + + template + struct default_value_traits + { + typedef char* value_type; + typedef char query_type[N]; + typedef details::buffer image_type; + + static void + set_value (char* const& v, + const char* b, + std::size_t n, + bool is_null) + { + c_array_value_traits_base::set_value (v, b, n, is_null, N); + } + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const char* v) + { + c_array_value_traits_base::set_image (b, c, n, is_null, v, N); + } + }; + + // std::array (string) specialization. + // +#ifdef ODB_CXX11 + template + struct default_value_traits, id_string> + { + typedef std::array value_type; + typedef std::array query_type; + typedef details::buffer image_type; + + static void + set_value (value_type& v, + const char* b, + std::size_t n, + bool is_null) + { + c_array_value_traits_base::set_value (v.data (), b, n, is_null, N); + } + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const value_type& v) + { + c_array_value_traits_base::set_image (b, c, n, is_null, v.data (), N); + } + }; +#endif + + // char specialization. + // + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits + { + typedef char value_type; + typedef char query_type; + typedef details::buffer image_type; + + static void + set_value (char& v, + const char* b, + std::size_t n, + bool is_null) + { + c_array_value_traits_base::set_value (&v, b, n, is_null, 1); + } + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + char v) + { + c_array_value_traits_base::set_image (b, c, n, is_null, &v, 1); + } + }; + + // std::string specialization for long_string. + // + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits + { + typedef std::string value_type; + typedef std::string query_type; + typedef long_callback image_type; + + static void + set_value (std::string& v, + result_callback_type& cb, + void*& context) + { + cb = &result_callback; + context = &v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const std::string& v) + { + is_null = false; + cb = ¶m_callback; + context = &v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); + }; + + // char*/const char* specialization for long_string. + // + class LIBODB_MSSQL_EXPORT c_string_long_value_traits + { + public: + typedef const char* value_type; + typedef long_callback image_type; + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const char* v) + { + is_null = false; + cb = ¶m_callback; + context = v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + }; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits< + char*, id_long_string>: c_string_long_value_traits {}; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits< + const char*, id_long_string>: c_string_long_value_traits {}; + + // char[N] specialization for long_string. + // + template + struct c_array_long_value_traits_base + { + static void + set_value (char* const& v, + result_callback_type& cb, + void*& context) + { + cb = &result_callback; + context = v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const char* v) + { + is_null = false; + cb = ¶m_callback; + context = v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); + }; + + template + struct default_value_traits + { + typedef char* value_type; + typedef char query_type[N]; + typedef long_callback image_type; + + static void + set_value (char* const& v, + result_callback_type& cb, + void*& context) + { + c_array_long_value_traits_base::set_value (v, cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const char* v) + { + c_array_long_value_traits_base::set_image (cb, context, is_null, v); + } + }; + + // std::array (long_string) specialization. + // +#ifdef ODB_CXX11 + template + struct default_value_traits, id_long_string> + { + typedef std::array value_type; + typedef std::array query_type; + typedef long_callback image_type; + + static void + set_value (value_type& v, + result_callback_type& cb, + void*& context) + { + c_array_long_value_traits_base::set_value (v.data (), cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const value_type& v) + { + c_array_long_value_traits_base::set_image ( + cb, context, is_null, v.data ()); + } + }; +#endif + + // std::wstring specialization for nstring. + // + template + struct wstring_functions + { + static void + assign (std::wstring& s, const ucs2_char* b, std::size_t n) + { + s.assign (b, b + n); + } + + static void + assign (ucs2_char* b, const wchar_t* s, std::size_t n) + { + for (std::size_t i (0); i < n; ++i) + b[i] = static_cast (s[i]); + } + + // Even though this is not used when ucs2_char == wchar_t, the + // compiler will still compile the signatures and complain. + // +#ifndef _WIN32 + static void + assign (wchar_t* s, const ucs2_char* b, std::size_t n) + { + for (std::size_t i (0); i < n; ++i) + s[i] = static_cast (b[i]); + } +#endif + }; + + template <> + struct LIBODB_MSSQL_EXPORT wstring_functions + { + static void + assign (std::wstring& s, const ucs2_char* b, std::size_t n) + { + s.assign (reinterpret_cast (b), n); + } + + static void + assign (ucs2_char* b, const wchar_t* s, std::size_t n) + { + std::memcpy (b, s, n * sizeof (ucs2_char)); + } + + // On Windows ucs2_char is wchar_t which makes this function + // the same as the one above. + // +#ifndef _WIN32 + static void + assign (wchar_t* s, const ucs2_char* b, std::size_t n) + { + std::memcpy (s, b, n * sizeof (ucs2_char)); + } +#endif + }; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits + { + typedef std::wstring value_type; + typedef std::wstring query_type; + typedef ucs2_char* image_type; + + typedef wstring_functions<> functions; + + static void + set_value (std::wstring& v, + const ucs2_char* b, + std::size_t n, + bool is_null) + { + if (!is_null) + functions::assign (v, b, n); + else + v.erase (); + } + + static void + set_image (ucs2_char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const std::wstring& v) + { + is_null = false; + n = v.size (); + + if (n > c) + n = c; + + if (n != 0) + functions::assign (b, v.c_str (), n); + } + }; + + // wchar_t*/const wchar_t* specialization for nstring. + // + class LIBODB_MSSQL_EXPORT c_wstring_value_traits + { + public: + typedef const wchar_t* value_type; + typedef ucs2_char* image_type; + + typedef wstring_functions<> functions; + + static void + set_image (ucs2_char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const wchar_t* v) + { + is_null = false; + n = std::wcslen (v); + + if (n > c) + n = c; + + if (n != 0) + functions::assign (b, v, n); + } + }; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits: + c_wstring_value_traits {}; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits< + const wchar_t*, id_nstring>: c_wstring_value_traits {}; + + // wchar_t[N] specialization. + // + struct LIBODB_MSSQL_EXPORT c_warray_value_traits_base + { + typedef wstring_functions<> functions; + + static void + set_value (wchar_t* const& v, + const ucs2_char* b, + std::size_t n, + bool is_null, + std::size_t N); + + static void + set_image (ucs2_char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const wchar_t* v, + std::size_t N); + }; + + template + struct default_value_traits + { + typedef wchar_t* value_type; + typedef wchar_t query_type[N]; + typedef details::buffer image_type; + + static void + set_value (wchar_t* const& v, + const ucs2_char* b, + std::size_t n, + bool is_null) + { + c_warray_value_traits_base::set_value (v, b, n, is_null, N); + } + + static void + set_image (ucs2_char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const wchar_t* v) + { + c_warray_value_traits_base::set_image (b, c, n, is_null, v, N); + } + }; + + // std::array (string) specialization. + // +#ifdef ODB_CXX11 + template + struct default_value_traits, id_nstring> + { + typedef std::array value_type; + typedef std::array query_type; + typedef details::buffer image_type; + + static void + set_value (value_type& v, + const ucs2_char* b, + std::size_t n, + bool is_null) + { + c_warray_value_traits_base::set_value (v.data (), b, n, is_null, N); + } + + static void + set_image (ucs2_char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const value_type& v) + { + c_warray_value_traits_base::set_image (b, c, n, is_null, v.data (), N); + } + }; +#endif + + // wchar_t specialization. + // + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits + { + typedef wchar_t value_type; + typedef wchar_t query_type; + typedef details::buffer image_type; + + static void + set_value (wchar_t& v, + const ucs2_char* b, + std::size_t n, + bool is_null) + { + c_warray_value_traits_base::set_value (&v, b, n, is_null, 1); + } + + static void + set_image (ucs2_char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + wchar_t v) + { + c_warray_value_traits_base::set_image (b, c, n, is_null, &v, 1); + } + }; + + // std::wstring specialization for long_nstring. + // + template + struct wstring_long_value_traits; + + template <> + struct LIBODB_MSSQL_EXPORT wstring_long_value_traits<2> + { + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); + }; + +#ifndef _WIN32 + template <> + struct LIBODB_MSSQL_EXPORT wstring_long_value_traits<4> + { + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); + }; +#endif + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits + { + typedef std::wstring value_type; + typedef std::wstring query_type; + typedef long_callback image_type; + + static void + set_value (std::wstring& v, + result_callback_type& cb, + void*& context) + { + cb = &wstring_long_value_traits<>::result_callback; + context = &v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const std::wstring& v) + { + is_null = false; + cb = &wstring_long_value_traits<>::param_callback; + context = &v; + } + }; + + // wchar_t*/const wchar_t* specialization for long_nstring. + // + template + struct c_wstring_long_value_traits; + + template <> + struct LIBODB_MSSQL_EXPORT c_wstring_long_value_traits<2> + { + typedef const wchar_t* value_type; + typedef long_callback image_type; + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const wchar_t* v) + { + is_null = false; + cb = ¶m_callback; + context = v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + }; + +#ifndef _WIN32 + template <> + struct LIBODB_MSSQL_EXPORT c_wstring_long_value_traits<4> + { + typedef const wchar_t* value_type; + typedef long_callback image_type; + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const wchar_t* v) + { + is_null = false; + cb = ¶m_callback; + context = v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + }; +#endif + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits< + wchar_t*, id_long_nstring>: c_wstring_long_value_traits<> {}; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits< + const wchar_t*, id_long_nstring>: c_wstring_long_value_traits<> {}; + + // char[N] specialization for long_nstring. + // + template + struct c_warray_long_value_traits_base; + + template + struct c_warray_long_value_traits_base + { + static void + set_value (wchar_t* const& v, + result_callback_type& cb, + void*& context) + { + cb = &result_callback; + context = v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const wchar_t* v) + { + is_null = false; + cb = ¶m_callback; + context = v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); + }; + +#ifndef _WIN32 + template + struct c_warray_long_value_traits_base + { + static void + set_value (wchar_t* const& v, + result_callback_type& cb, + void*& context) + { + cb = &result_callback; + context = v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const wchar_t* v) + { + is_null = false; + cb = ¶m_callback; + context = v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); + }; +#endif + + template + struct default_value_traits + { + typedef wchar_t* value_type; + typedef wchar_t query_type[N]; + typedef long_callback image_type; + + static void + set_value (wchar_t* const& v, + result_callback_type& cb, + void*& context) + { + c_warray_long_value_traits_base::set_value (v, cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const wchar_t* v) + { + c_warray_long_value_traits_base::set_image ( + cb, context, is_null, v); + } + }; + + // std::array (long_nstring) specialization. + // +#ifdef ODB_CXX11 + template + struct default_value_traits, id_long_nstring> + { + typedef std::array value_type; + typedef std::array query_type; + typedef long_callback image_type; + + static void + set_value (value_type& v, + result_callback_type& cb, + void*& context) + { + c_warray_long_value_traits_base::set_value ( + v.data (), cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const value_type& v) + { + c_warray_long_value_traits_base::set_image ( + cb, context, is_null, v.data ()); + } + }; +#endif + + // std::vector (buffer) specialization for binary. + // + template + struct vector_binary_value_traits + { + typedef std::vector value_type; + typedef std::vector query_type; + typedef char* image_type; + + static void + set_value (value_type& v, const char* b, std::size_t n, bool is_null) + { + if (!is_null) + { + const C* cb (reinterpret_cast (b)); + v.assign (cb, cb + n); + } + else + v.clear (); + } + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const value_type& v) + { + is_null = false; + n = v.size (); + + if (n > c) + n = c; + + // std::vector::data() may not be available in older compilers. + // + if (n != 0) + std::memcpy (b, &v.front (), n); + } + }; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits, + id_binary>: + vector_binary_value_traits + { + }; + + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits, + id_binary>: + vector_binary_value_traits + { + }; + + // C array (buffer) specialization for binary. + // + template + struct c_array_binary_value_traits + { + typedef C* value_type; + typedef C query_type[N]; + typedef char* image_type; + + static void + set_value (C* const& v, const char* b, std::size_t n, bool is_null) + { + if (!is_null) + std::memcpy (v, b, n < N ? n : N); + else + std::memset (v, 0, N); + } + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const C* v) + { + is_null = false; + n = c > N ? N : c; + std::memcpy (b, v, n); + } + }; + + template + struct default_value_traits: + c_array_binary_value_traits + { + }; + + template + struct default_value_traits: + c_array_binary_value_traits + { + }; + +#ifdef ODB_CXX11 + // std::array (buffer) specialization for binary. + // + template + struct array_binary_value_traits + { + typedef std::array value_type; + typedef value_type query_type; + typedef char* image_type; + + static void + set_value (value_type& v, const char* b, std::size_t n, bool is_null) + { + if (!is_null) + std::memcpy (v.data (), b, n < N ? n : N); + else + std::memset (v.data (), 0, N); + } + + static void + set_image (char* b, + std::size_t c, + std::size_t& n, + bool& is_null, + const value_type& v) + { + is_null = false; + n = c > N ? N : c; + std::memcpy (b, v.data (), n); + } + }; + + template + struct default_value_traits, id_binary>: + array_binary_value_traits + { + }; + + template + struct default_value_traits, id_binary>: + array_binary_value_traits + { + }; +#endif + + // std::vector (buffer) specialization for long_binary. + // + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits, + id_long_binary> + { + typedef std::vector value_type; + typedef std::vector query_type; + typedef long_callback image_type; + + static void + set_value (value_type& v, + result_callback_type& cb, + void*& context) + { + cb = &result_callback; + context = &v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const value_type& v) + { + is_null = false; + cb = ¶m_callback; + context = &v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); + }; + + // std::vector (buffer) specialization for long_binary. + // + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits, + id_long_binary> + { + typedef std::vector value_type; + typedef std::vector query_type; + typedef long_callback image_type; + + static void + set_value (value_type& v, + result_callback_type& cb, + void*& context) + { + cb = &result_callback; + context = &v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const value_type& v) + { + is_null = false; + cb = ¶m_callback; + context = &v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); + }; + + // C array (buffer) specialization for long_binary. + // + template + struct c_array_long_binary_value_traits + { + static void + set_value (C* const& v, + result_callback_type& cb, + void*& context) + { + cb = &result_callback; + context = v; + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const C* v) + { + is_null = false; + cb = ¶m_callback; + context = v; + } + + static void + param_callback (const void* context, + std::size_t* position, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buffer, + std::size_t tmp_capacity); + + static void + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity); + }; + + template + struct default_value_traits: + c_array_long_binary_value_traits + { + typedef char* value_type; + typedef char query_type[N]; + typedef long_callback image_type; + }; + + template + struct default_value_traits: + c_array_long_binary_value_traits + { + typedef unsigned char* value_type; + typedef unsigned char query_type[N]; + typedef long_callback image_type; + }; + +#ifdef ODB_CXX11 + // std::array (buffer) specialization for long_binary. + // + template + struct default_value_traits, id_long_binary> + { + typedef std::array value_type; + typedef value_type query_type; + typedef long_callback image_type; + + static void + set_value (value_type& v, + result_callback_type& cb, + void*& context) + { + c_array_long_binary_value_traits::set_value ( + v.data (), cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const value_type& v) + { + c_array_long_binary_value_traits::set_image ( + cb, context, is_null, v.data ()); + } + }; + + template + struct default_value_traits, id_long_binary> + { + typedef std::array value_type; + typedef value_type query_type; + typedef long_callback image_type; + + static void + set_value (value_type& v, + result_callback_type& cb, + void*& context) + { + c_array_long_binary_value_traits::set_value ( + v.data (), cb, context); + } + + static void + set_image (param_callback_type& cb, + const void*& context, + bool& is_null, + const value_type& v) + { + c_array_long_binary_value_traits::set_image ( + cb, context, is_null, v.data ()); + } + }; +#endif + + // GUID specialization for uniqueidentifier. + // +#ifdef _WIN32 + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits + { + typedef GUID value_type; + typedef GUID query_type; + typedef uniqueidentifier image_type; + + static void + set_value (GUID& v, const uniqueidentifier& i, bool is_null) + { + if (!is_null) + std::memcpy (&v, &i, 16); + else + std::memset (&v, 0, 16); + } + + static void + set_image (uniqueidentifier& i, bool& is_null, const GUID& v) + { + is_null = false; + std::memcpy (&i, &v, 16); + } + }; +#endif + + // char[16] specialization for uniqueidentifier. + // + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits + { + typedef char* value_type; + typedef char query_type[16]; + typedef uniqueidentifier image_type; + + static void + set_value (char* const& v, const uniqueidentifier& i, bool is_null) + { + if (!is_null) + std::memcpy (v, &i, 16); + else + std::memset (v, 0, 16); + } + + static void + set_image (uniqueidentifier& i, bool& is_null, const char* v) + { + is_null = false; + std::memcpy (&i, v, 16); + } + }; + + // unsigned long long specialization for rowversion. + // + template <> + struct LIBODB_MSSQL_EXPORT default_value_traits + { + typedef unsigned long long value_type; + typedef unsigned long long query_type; + typedef unsigned char* image_type; + + static void + set_value (unsigned long long& v, const unsigned char* i, bool is_null) + { + if (!is_null) + { + // The value is in the big-endian format. + // + unsigned char* p (reinterpret_cast (&v)); + p[0] = i[7]; + p[1] = i[6]; + p[2] = i[5]; + p[3] = i[4]; + p[4] = i[3]; + p[5] = i[2]; + p[6] = i[1]; + p[7] = i[0]; + } + else + v = 0; + } + + static void + set_image (unsigned char* i, bool& is_null, unsigned long long v) + { + is_null = false; + + // The value is in the big-endian format. + // + const unsigned char* p (reinterpret_cast (&v)); + i[0] = p[7]; + i[1] = p[6]; + i[2] = p[5]; + i[3] = p[4]; + i[4] = p[3]; + i[5] = p[2]; + i[6] = p[1]; + i[7] = p[0]; + } + }; + + // + // type_traits + // + + template + struct default_type_traits; + + template + class type_traits: public default_type_traits + { + }; + + // Integral types. + // + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_bit; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_tinyint; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_tinyint; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_smallint; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_smallint; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_int; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_int; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_bigint; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_bigint; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_bigint; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_bigint; + }; + + // Float types. + // + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_float4; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_float8; + }; + + // String types. + // + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_long_string; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_long_string; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_long_string; + }; + + template + struct default_type_traits + { + // Use short string by default to minimize code bloat. Can + // always be overridden with _val()/_ref(). + // + static const database_type_id db_type_id = id_string; + }; + +#ifdef ODB_CXX11 + template + struct default_type_traits > + { + // Ditto. + // + static const database_type_id db_type_id = id_string; + }; +#endif + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_string; + }; + + // Wide string types. + // + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_long_nstring; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_long_nstring; + }; + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_long_nstring; + }; + + template + struct default_type_traits + { + // Use short string by default to minimize code bloat. Can + // always be overridden with _val()/_ref(). + // + static const database_type_id db_type_id = id_nstring; + }; + +#ifdef ODB_CXX11 + template + struct default_type_traits > + { + // Ditto. + // + static const database_type_id db_type_id = id_nstring; + }; +#endif + + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_nstring; + }; + + // Binary types. + // + template + struct default_type_traits + { + static const database_type_id db_type_id = id_long_binary; + }; + + template <> + struct default_type_traits > + { + static const database_type_id db_type_id = id_long_binary; + }; + + template <> + struct default_type_traits > + { + static const database_type_id db_type_id = id_long_binary; + }; + +#ifdef ODB_CXX11 + template + struct default_type_traits > + { + static const database_type_id db_type_id = id_long_binary; + }; +#endif + + // GUID. + // +#ifdef _WIN32 + template <> + struct default_type_traits + { + static const database_type_id db_type_id = id_uniqueidentifier; + }; +#endif + } +} + +#include + +#include + +#endif // ODB_MSSQL_TRAITS_HXX diff --git a/libodb-mssql/odb/mssql/traits.txx b/libodb-mssql/odb/mssql/traits.txx new file mode 100644 index 0000000..683054c --- /dev/null +++ b/libodb-mssql/odb/mssql/traits.txx @@ -0,0 +1,399 @@ +// file : odb/mssql/traits.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +namespace odb +{ + namespace mssql + { + // + // wrapped_value_traits + // + template + void wrapped_value_traits:: + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buffer, + std::size_t tmp_capacity) + { + W& v (*static_cast (context)); + + if (chunk == chunk_null) + wtraits::set_null (v); + else + { + long_callback& c (*static_cast (*buffer)); + + // Redirect all further calls. + // + vtraits::set_value (wtraits::set_ref (v), + c.callback.result, + c.context.result); + + // Forward this call. + // + c.callback.result ( + c.context.result, + position, + buffer, + size, + chunk, + size_left, + tmp_buffer, + tmp_capacity); + } + } + + // + // c_array_long_value_traits_base + // + template + void c_array_long_value_traits_base:: + param_callback (const void* context, + std::size_t*, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void*, + std::size_t) + { + // Figure out the length. We cannot use strlen since it may + // not be 0-terminated (strnlen is not standard). + // + size_t n (0); + for (; n != N && static_cast (context)[n] != '\0'; ++n); + + *buffer = context; + *size = n; + *chunk = chunk_one; + } + + template + void c_array_long_value_traits_base:: + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t, + void* tmp_buf, + std::size_t tmp_capacity) + { + char* p (static_cast (context)); + + switch (chunk) + { + case chunk_null: + case chunk_one: + { + *p = '\0'; + break; + } + case chunk_first: + { + *buffer = p; + *size = N; + break; + } + case chunk_next: + { + // ODBC insists on appending '\0' to each chunk it returns. + // As a result, we can get here if the last character did not + // fit into our buffer. There could also be more data but since + // there is no way to stop until we read all the data, dump + // the remainder into the temporary buffer. + // + + // Use position to indicate whether this is the first "next + // chunk". + // + if (*position == 0) + *position = 1; + else if (*position == 1) + { + p[N - 1] = *static_cast (tmp_buf); + *position = 2; + } + + *buffer = tmp_buf; + *size = tmp_capacity; + break; + } + case chunk_last: + { + if (*position == 0) + { + if (*size < N) // Append '\0' if there is space. + p[*size] = '\0'; + } + else if (*position == 1) + p[N - 1] = *static_cast (tmp_buf); + + break; + } + } + } + + // + // c_warray_long_value_traits_base<2> + // + template + void c_warray_long_value_traits_base:: + param_callback (const void* context, + std::size_t*, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void*, + std::size_t) + { + // Figure out the length. We cannot use wcslen since it may + // not be 0-terminated (wcsnlen is not standard). + // + size_t n (0); + for (; n != N && static_cast (context)[n] != L'\0'; ++n); + + *buffer = context; + *size = n * 2; // In bytes. + *chunk = chunk_one; + } + + template + void c_warray_long_value_traits_base:: + result_callback (void* context, + std::size_t* position, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t, + void* tmp_buf, + std::size_t tmp_capacity) + { + wchar_t* p (static_cast (context)); + + switch (chunk) + { + case chunk_null: + case chunk_one: + { + *p = L'\0'; + break; + } + case chunk_first: + { + *buffer = p; + *size = N * 2; // In bytes + break; + } + case chunk_next: + { + // ODBC insists on appending '\0' to each chunk it returns. + // As a result, we can get here if the last character did not + // fit into our buffer. There could also be more data but since + // there is no way to stop until we read all the data, dump + // the remainder into the temporary buffer. + // + + // Use position to indicate whether this is the first "next + // chunk". + // + if (*position == 0) + *position = 1; + else if (*position == 1) + { + p[N - 1] = *static_cast (tmp_buf); + *position = 2; + } + + *buffer = tmp_buf; + *size = tmp_capacity; + break; + } + case chunk_last: + { + if (*position == 0) + { + size_t n (*size / 2); // In wide characters. + if (n < N) // Append '\0' if there is space. + p[n] = L'\0'; + } + else if (*position == 1) + p[N - 1] = *static_cast (tmp_buf); + + break; + } + } + } + +#ifndef _WIN32 + // + // c_warray_long_value_traits_base<4> + // + template + void c_warray_long_value_traits_base:: + param_callback (const void* context, + std::size_t* pos, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void* tmp_buf, + std::size_t tmp_capacity) + { + // Here we cannot just return the pointer to the underlying buffer + // since the character sizes are different. Instead we copy the + // data to the temporary buffer. + // + ucs2_char* d (static_cast (tmp_buf)); + const wchar_t* s (static_cast (context) + *pos); + + size_t n (0); + tmp_capacity /= 2; // In UCS-2 character. + for (const wchar_t* e (s + N); + s != e && *s != L'\0' && n != tmp_capacity; + ++n, ++s) + d[n] = static_cast (*s); + + *buffer = d; + *size = n * 2; // In bytes. + *chunk = (n != tmp_capacity ? chunk_last : chunk_next); + + if (*pos == 0) + { + if (*chunk == chunk_last) + *chunk = chunk_one; + else + *chunk = chunk_first; + } + + *pos += n; + } + + template + void c_warray_long_value_traits_base:: + result_callback (void* context, + std::size_t* pos, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t, + void* tmp_buf, + std::size_t tmp_capacity) + { + wchar_t* d (static_cast (context)); + const ucs2_char* s (static_cast (tmp_buf)); + + // Again, we cannot do direct buffer copy and have to use the + // temporary buffer instead. + // + switch (chunk) + { + case chunk_null: + case chunk_one: + { + *d = L'\0'; + break; + } + case chunk_first: + { + break; + } + case chunk_next: + case chunk_last: + { + // Append the data from the temporary buffer. + // + if (*pos < N) + { + *size /= 2; // In UCS-2 characters. + size_t n (N - *pos); + n = *size < n ? *size : n; + + wstring_functions<>::assign (d + *pos, s, n); + *pos += n; + + if (*pos < N) // Append '\0' if there is space. + d[*pos] = L'\0'; + } + + break; + } + } + + if (chunk == chunk_first || chunk == chunk_next) + { + *buffer = tmp_buf; + *size = tmp_capacity; + } + } +#endif + + // + // c_array_long_binary_value_traits + // + template + void c_array_long_binary_value_traits:: + param_callback (const void* context, + std::size_t*, + const void** buffer, + std::size_t* size, + chunk_type* chunk, + void*, + std::size_t) + { + *buffer = context; + *size = N; + *chunk = chunk_one; + } + + template + void c_array_long_binary_value_traits:: + result_callback (void* context, + std::size_t*, + void** buffer, + std::size_t* size, + chunk_type chunk, + std::size_t size_left, + void* tmp_buf, + std::size_t tmp_capacity) + { + // The code is similar to the vector specialization. + // + switch (chunk) + { + case chunk_null: + case chunk_one: + { + std::memset (context, 0, N); + break; + } + case chunk_first: + { + assert (size_left != 0); + + *buffer = context; + *size = size_left < N ? size_left : N; + break; + } + case chunk_next: + { + // We can get here if total size is greater than N. There is + // no way to stop until we read all the data, so dump the + // remainder into the temporary buffer. + // + *buffer = tmp_buf; + *size = tmp_capacity; + break; + } + case chunk_last: + { + break; + } + } + } + } +} diff --git a/libodb-mssql/odb/mssql/transaction-impl.cxx b/libodb-mssql/odb/mssql/transaction-impl.cxx new file mode 100644 index 0000000..a44e83f --- /dev/null +++ b/libodb-mssql/odb/mssql/transaction-impl.cxx @@ -0,0 +1,103 @@ +// file : odb/mssql/transaction-impl.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +#include +#include +#include +#include +#include + +namespace odb +{ + namespace mssql + { + transaction_impl:: + transaction_impl (database_type& db) + : odb::transaction_impl (db) + { + } + + transaction_impl:: + transaction_impl (connection_ptr c) + : odb::transaction_impl (c->database (), *c), connection_ (c) + { + } + + transaction_impl:: + ~transaction_impl () + { + } + + void transaction_impl:: + start () + { + // Grab a connection if we don't already have one. + // + if (connection_ == 0) + { + connection_ = static_cast (database_).connection (); + odb::transaction_impl::connection_ = connection_.get (); + } + + { + odb::tracer* t; + if ((t = connection_->tracer ()) || (t = database_.tracer ())) + t->execute (*connection_, "BEGIN"); + } + + // In ODBC a transaction is started automatically before the first + // statement is executed. + // + } + + void transaction_impl:: + commit () + { + // Invalidate query results. + // + connection_->invalidate_results (); + + { + odb::tracer* t; + if ((t = connection_->tracer ()) || (t = database_.tracer ())) + t->execute (*connection_, "COMMIT"); + } + + SQLRETURN r ( + SQLEndTran (SQL_HANDLE_DBC, connection_->handle (), SQL_COMMIT)); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, *connection_, true); + + // Release the connection. + // + connection_.reset (); + } + + void transaction_impl:: + rollback () + { + // Invalidate query results. + // + connection_->invalidate_results (); + + { + odb::tracer* t; + if ((t = connection_->tracer ()) || (t = database_.tracer ())) + t->execute (*connection_, "ROLLBACK"); + } + + SQLRETURN r ( + SQLEndTran (SQL_HANDLE_DBC, connection_->handle (), SQL_ROLLBACK)); + + if (!SQL_SUCCEEDED (r)) + translate_error (r, *connection_, true); + + // Release the connection. + // + connection_.reset (); + } + } +} diff --git a/libodb-mssql/odb/mssql/transaction-impl.hxx b/libodb-mssql/odb/mssql/transaction-impl.hxx new file mode 100644 index 0000000..f7189f2 --- /dev/null +++ b/libodb-mssql/odb/mssql/transaction-impl.hxx @@ -0,0 +1,49 @@ +// file : odb/mssql/transaction-impl.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_TRANSACTION_IMPL_HXX +#define ODB_MSSQL_TRANSACTION_IMPL_HXX + +#include + +#include + +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class LIBODB_MSSQL_EXPORT transaction_impl: public odb::transaction_impl + { + public: + typedef mssql::database database_type; + typedef mssql::connection connection_type; + + transaction_impl (database_type&); + transaction_impl (connection_ptr); + + virtual + ~transaction_impl (); + + virtual void + start (); + + virtual void + commit (); + + virtual void + rollback (); + + private: + connection_ptr connection_; + }; + } +} + +#include + +#endif // ODB_MSSQL_TRANSACTION_IMPL_HXX diff --git a/libodb-mssql/odb/mssql/transaction.cxx b/libodb-mssql/odb/mssql/transaction.cxx new file mode 100644 index 0000000..bb51697 --- /dev/null +++ b/libodb-mssql/odb/mssql/transaction.cxx @@ -0,0 +1,26 @@ +// file : odb/mssql/transaction.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include + +#include + +namespace odb +{ + namespace mssql + { + transaction& transaction:: + current () + { + // While the impl type can be of the concrete type, the transaction + // object can be created as either odb:: or odb::mssql:: type. To + // work around that we are going to hard-cast one to the other + // relying on the fact that they have the same representation and + // no virtual functions. The former is checked in the tests. + // + odb::transaction& b (odb::transaction::current ()); + assert (dynamic_cast (&b.implementation ()) != 0); + return reinterpret_cast (b); + } + } +} diff --git a/libodb-mssql/odb/mssql/transaction.hxx b/libodb-mssql/odb/mssql/transaction.hxx new file mode 100644 index 0000000..8c86515 --- /dev/null +++ b/libodb-mssql/odb/mssql/transaction.hxx @@ -0,0 +1,88 @@ +// file : odb/mssql/transaction.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_TRANSACTION_HXX +#define ODB_MSSQL_TRANSACTION_HXX + +#include + +#include + +#include +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class transaction_impl; + + class LIBODB_MSSQL_EXPORT transaction: public odb::transaction + { + public: + typedef mssql::database database_type; + typedef mssql::connection connection_type; + + explicit + transaction (transaction_impl*, bool make_current = true); + + transaction (); + + // Return the database this transaction is on. + // + database_type& + database (); + + // Return the underlying database connection for this transaction. + // + connection_type& + connection (); + + connection_type& + connection (odb::database&); + + // Return current transaction or throw if there is no transaction + // in effect. + // + static transaction& + current (); + + // Set the current thread's transaction. + // + static void + current (transaction&); + + // SQL statement tracing. + // + public: + typedef mssql::tracer tracer_type; + + void + tracer (tracer_type& t) + { + odb::transaction::tracer (t); + } + + void + tracer (tracer_type* t) + { + odb::transaction::tracer (t); + } + + using odb::transaction::tracer; + + public: + transaction_impl& + implementation (); + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_TRANSACTION_HXX diff --git a/libodb-mssql/odb/mssql/transaction.ixx b/libodb-mssql/odb/mssql/transaction.ixx new file mode 100644 index 0000000..ac819bc --- /dev/null +++ b/libodb-mssql/odb/mssql/transaction.ixx @@ -0,0 +1,57 @@ +// file : odb/mssql/transaction.ixx +// license : ODB NCUEL; see accompanying LICENSE file + +#include +#include + +namespace odb +{ + namespace mssql + { + inline transaction:: + transaction (transaction_impl* impl, bool make_current) + : odb::transaction (impl, make_current) + { + } + + inline transaction:: + transaction () + : odb::transaction () + { + } + + inline transaction_impl& transaction:: + implementation () + { + // We can use static_cast here since we have an instance of + // mssql::transaction. + // + return static_cast ( + odb::transaction::implementation ()); + } + + inline transaction::database_type& transaction:: + database () + { + return static_cast (odb::transaction::database ()); + } + + inline transaction::connection_type& transaction:: + connection () + { + return static_cast (odb::transaction::connection ()); + } + + inline transaction::connection_type& transaction:: + connection (odb::database& db) + { + return static_cast (odb::transaction::connection (db)); + } + + inline void transaction:: + current (transaction& t) + { + odb::transaction::current (t); + } + } +} diff --git a/libodb-mssql/odb/mssql/version-build2-stub.hxx b/libodb-mssql/odb/mssql/version-build2-stub.hxx new file mode 100644 index 0000000..969ab3c --- /dev/null +++ b/libodb-mssql/odb/mssql/version-build2-stub.hxx @@ -0,0 +1,4 @@ +// file : odb/mssql/version-build2-stub.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#include diff --git a/libodb-mssql/odb/mssql/version-build2.hxx b/libodb-mssql/odb/mssql/version-build2.hxx new file mode 100644 index 0000000..e69de29 diff --git a/libodb-mssql/odb/mssql/version-build2.hxx.in b/libodb-mssql/odb/mssql/version-build2.hxx.in new file mode 100644 index 0000000..9f57dfe --- /dev/null +++ b/libodb-mssql/odb/mssql/version-build2.hxx.in @@ -0,0 +1,42 @@ +// file : odb/mssql/version-build2.hxx.in +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef LIBODB_MSSQL_VERSION // Note: using the version macro itself. + +// The numeric version format is AAAAABBBBBCCCCCDDDE where: +// +// AAAAA - major version number +// BBBBB - minor version number +// CCCCC - bugfix version number +// DDD - alpha / beta (DDD + 500) version number +// E - final (0) / snapshot (1) +// +// When DDDE is not 0, 1 is subtracted from AAAAABBBBBCCCCC. For example: +// +// Version AAAAABBBBBCCCCCDDDE +// +// 0.1.0 0000000001000000000 +// 0.1.2 0000000001000020000 +// 1.2.3 0000100002000030000 +// 2.2.0-a.1 0000200001999990010 +// 3.0.0-b.2 0000299999999995020 +// 2.2.0-a.1.z 0000200001999990011 +// +#define LIBODB_MSSQL_VERSION $libodb_mssql.version.project_number$ULL +#define LIBODB_MSSQL_VERSION_STR "$libodb_mssql.version.project$" +#define LIBODB_MSSQL_VERSION_ID "$libodb_mssql.version.project_id$" + +#define LIBODB_MSSQL_VERSION_MAJOR $libodb_mssql.version.major$ +#define LIBODB_MSSQL_VERSION_MINOR $libodb_mssql.version.minor$ +#define LIBODB_MSSQL_VERSION_PATCH $libodb_mssql.version.patch$ + +#define LIBODB_MSSQL_PRE_RELEASE $libodb_mssql.version.pre_release$ + +#define LIBODB_MSSQL_SNAPSHOT $libodb_mssql.version.snapshot_sn$ULL +#define LIBODB_MSSQL_SNAPSHOT_ID "$libodb_mssql.version.snapshot_id$" + +#include + +$libodb.check(LIBODB_VERSION, LIBODB_SNAPSHOT)$ + +#endif // LIBODB_MSSQL_VERSION diff --git a/libodb-mssql/odb/mssql/version.hxx b/libodb-mssql/odb/mssql/version.hxx new file mode 100644 index 0000000..5b6cc56 --- /dev/null +++ b/libodb-mssql/odb/mssql/version.hxx @@ -0,0 +1,48 @@ +// file : odb/mssql/version.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifdef LIBODB_MSSQL_BUILD2 +# include +#else + +#ifndef ODB_MSSQL_VERSION_HXX +#define ODB_MSSQL_VERSION_HXX + +#include + +#include +#include + +// Version format is AABBCCDD where +// +// AA - major version number +// BB - minor version number +// CC - bugfix version number +// DD - alpha / beta (DD + 50) version number +// +// When DD is not 00, 1 is subtracted from AABBCC. For example: +// +// Version AABBCCDD +// 2.0.0 02000000 +// 2.1.0 02010000 +// 2.1.1 02010100 +// 2.2.0.a1 02019901 +// 3.0.0.b2 02999952 +// + +// Check that we have compatible ODB version. +// +#if ODB_VERSION != 20476 +# error incompatible odb interface version detected +#endif + +// libodb-mssql version: odb interface version plus the bugfix +// version. +// +#define LIBODB_MSSQL_VERSION 2049976 +#define LIBODB_MSSQL_VERSION_STR "2.5.0-b.26" + +#include + +#endif // ODB_MSSQL_VERSION_HXX +#endif // LIBODB_MSSQL_BUILD2 diff --git a/libodb-mssql/odb/mssql/view-result.hxx b/libodb-mssql/odb/mssql/view-result.hxx new file mode 100644 index 0000000..41e5b8e --- /dev/null +++ b/libodb-mssql/odb/mssql/view-result.hxx @@ -0,0 +1,85 @@ +// file : odb/mssql/view-result.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_VIEW_RESULT_HXX +#define ODB_MSSQL_VIEW_RESULT_HXX + +#include + +#include // std::size_t + +#include +#include + +#include + +#include +#include // query_base, view_statements +#include +#include + +namespace odb +{ + namespace mssql + { + template + class view_result_impl: public odb::view_result_impl + { + public: + typedef odb::view_result_impl base_type; + + typedef typename base_type::view_type view_type; + typedef typename base_type::pointer_type pointer_type; + + typedef view_traits_impl view_traits; + typedef typename base_type::pointer_traits pointer_traits; + + typedef view_statements statements_type; + + virtual + ~view_result_impl (); + + view_result_impl (const query_base&, + details::shared_ptr, + statements_type&, + const schema_version_migration*); + + virtual void + load (view_type&); + + virtual void + next (); + + virtual void + cache (); + + virtual std::size_t + size (); + + virtual void + invalidate (); + + using base_type::current; + + private: + typedef mssql::change_callback change_callback_type; + + static void + change_callback (void* context); + + private: + details::shared_ptr statement_; + statements_type& statements_; + view_traits_calls tc_; + bool can_load_; + bool use_copy_; + typename view_traits::image_type* image_copy_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_VIEW_RESULT_HXX diff --git a/libodb-mssql/odb/mssql/view-result.txx b/libodb-mssql/odb/mssql/view-result.txx new file mode 100644 index 0000000..7818d36 --- /dev/null +++ b/libodb-mssql/odb/mssql/view-result.txx @@ -0,0 +1,153 @@ +// file : odb/mssql/view-result.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include +#include // result_not_cached + +#include // long_data_reload +#include + +namespace odb +{ + namespace mssql + { + template + view_result_impl:: + ~view_result_impl () + { + invalidate (); + } + + template + void view_result_impl:: + invalidate () + { + change_callback_type& cc (statements_.image ().change_callback_); + + if (cc.context == this) + { + cc.callback = 0; + cc.context = 0; + } + + delete image_copy_; + image_copy_ = 0; + + if (!this->end_) + { + statement_->free_result (); + this->end_ = true; + } + + statement_.reset (); + } + + template + view_result_impl:: + view_result_impl (const query_base&, + details::shared_ptr statement, + statements_type& statements, + const schema_version_migration* svm) + : base_type (statements.connection ()), + statement_ (statement), + statements_ (statements), + tc_ (svm), + use_copy_ (false), + image_copy_ (0) + { + } + + template + void view_result_impl:: + load (view_type& view) + { + if (!can_load_) + throw long_data_reload (); + + view_traits::callback (this->db_, view, callback_event::pre_load); + + tc_.init (view, + use_copy_ ? *image_copy_ : statements_.image (), + &this->db_); + + // If we are using a copy, make sure the callback information for + // long data also comes from the copy. + // + can_load_ = !statement_->stream_result ( + use_copy_ ? &statements_.image () : 0, + use_copy_ ? image_copy_ : 0); + + view_traits::callback (this->db_, view, callback_event::post_load); + } + + template + void view_result_impl:: + next () + { + can_load_ = true; + this->current (pointer_type ()); + + typename view_traits::image_type& im (statements_.image ()); + change_callback_type& cc (im.change_callback_); + + if (cc.context == this) + { + cc.callback = 0; + cc.context = 0; + } + + use_copy_ = false; + + if (im.version != statements_.image_version ()) + { + binding& b (statements_.image_binding ()); + tc_.bind (b.bind, im); + statements_.image_version (im.version); + b.version++; + } + + if (statement_->fetch () == select_statement::no_data) + { + statement_->free_result (); + this->end_ = true; + } + else + { + cc.callback = &change_callback; + cc.context = this; + } + } + + template + void view_result_impl:: + cache () + { + } + + template + std::size_t view_result_impl:: + size () + { + throw result_not_cached (); + } + + template + void view_result_impl:: + change_callback (void* c) + { + view_result_impl* r (static_cast*> (c)); + + typename view_traits::image_type& im (r->statements_.image ()); + + if (r->image_copy_ == 0) + r->image_copy_ = new typename view_traits::image_type (im); + else + *r->image_copy_ = im; + + im.change_callback_.callback = 0; + im.change_callback_.context = 0; + + r->use_copy_ = true; + } + } +} diff --git a/libodb-mssql/odb/mssql/view-statements.hxx b/libodb-mssql/odb/mssql/view-statements.hxx new file mode 100644 index 0000000..1742cab --- /dev/null +++ b/libodb-mssql/odb/mssql/view-statements.hxx @@ -0,0 +1,83 @@ +// file : odb/mssql/view-statements.hxx +// license : ODB NCUEL; see accompanying LICENSE file + +#ifndef ODB_MSSQL_VIEW_STATEMENTS_HXX +#define ODB_MSSQL_VIEW_STATEMENTS_HXX + +#include + +#include // std::size_t + +#include +#include + +#include +#include +#include +#include + +namespace odb +{ + namespace mssql + { + template + class view_statements: public statements_base + { + public: + typedef T view_type; + typedef view_traits_impl view_traits; + typedef typename view_traits::pointer_type pointer_type; + typedef typename view_traits::image_type image_type; + + public: + view_statements (connection_type&); + + virtual + ~view_statements (); + + // View image. + // + image_type& + image () + { + return image_; + } + + std::size_t + image_version () const + { + return image_version_; + } + + void + image_version (std::size_t v) + { + image_version_ = v; + } + + binding& + image_binding () + { + return image_binding_; + } + + private: + view_statements (const view_statements&); + view_statements& operator= (const view_statements&); + + private: + image_type image_; + std::size_t image_version_; + binding image_binding_; + bind image_bind_[view_traits::column_count != 0 + ? view_traits::column_count + : 1]; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_VIEW_STATEMENTS_HXX diff --git a/libodb-mssql/odb/mssql/view-statements.txx b/libodb-mssql/odb/mssql/view-statements.txx new file mode 100644 index 0000000..e217523 --- /dev/null +++ b/libodb-mssql/odb/mssql/view-statements.txx @@ -0,0 +1,30 @@ +// file : odb/mssql/view-statements.txx +// license : ODB NCUEL; see accompanying LICENSE file + +#include // std::memset + +namespace odb +{ + namespace mssql + { + template + view_statements:: + ~view_statements () + { + } + + template + view_statements:: + view_statements (connection_type& conn) + : statements_base (conn), + image_binding_ (image_bind_, view_traits::column_count) + { + image_.version = 0; + image_version_ = 0; + + image_binding_.change_callback = image_.change_callback (); + + std::memset (image_bind_, 0, sizeof (image_bind_)); + } + } +} diff --git a/libodb-mssql/tests/.gitignore b/libodb-mssql/tests/.gitignore new file mode 100644 index 0000000..e54525b --- /dev/null +++ b/libodb-mssql/tests/.gitignore @@ -0,0 +1 @@ +driver diff --git a/libodb-mssql/tests/basics/buildfile b/libodb-mssql/tests/basics/buildfile new file mode 100644 index 0000000..ee213f5 --- /dev/null +++ b/libodb-mssql/tests/basics/buildfile @@ -0,0 +1,6 @@ +# file : tests/basics/buildfile +# license : ODB NCUEL; see accompanying LICENSE file + +import libs = libodb-mssql%lib{odb-mssql} + +exe{driver}: {hxx cxx}{*} $libs diff --git a/libodb-mssql/tests/basics/driver.cxx b/libodb-mssql/tests/basics/driver.cxx new file mode 100644 index 0000000..04d7231 --- /dev/null +++ b/libodb-mssql/tests/basics/driver.cxx @@ -0,0 +1,37 @@ +// file : tests/basics/driver.cxx +// license : ODB NCUEL; see accompanying LICENSE file + +// Basic test to make sure the library is usable. Functionality testing +// is done in the odb-tests package. + +#include +#include + +#include +#include +#include + +using namespace odb::mssql; + +int +main () +{ + { + std::ostringstream os; + database::print_usage (os); + assert (!os.str ().empty ()); + } + + // We can't really do much here since that would require a database. We can + // create a fake database object as long as we don't expect to get a valid + // connection. + // + database db ("john", "secret", "dummy whammy"); + + try + { + transaction t (db.begin ()); + assert (false); + } + catch (const database_exception&) {} +} diff --git a/libodb-mssql/tests/build/.gitignore b/libodb-mssql/tests/build/.gitignore new file mode 100644 index 0000000..4a730a3 --- /dev/null +++ b/libodb-mssql/tests/build/.gitignore @@ -0,0 +1,3 @@ +config.build +root/ +bootstrap/ diff --git a/libodb-mssql/tests/build/bootstrap.build b/libodb-mssql/tests/build/bootstrap.build new file mode 100644 index 0000000..895126c --- /dev/null +++ b/libodb-mssql/tests/build/bootstrap.build @@ -0,0 +1,8 @@ +# file : tests/build/bootstrap.build +# license : ODB NCUEL; see accompanying LICENSE file + +project = # Unnamed subproject. + +using config +using dist +using test diff --git a/libodb-mssql/tests/build/root.build b/libodb-mssql/tests/build/root.build new file mode 100644 index 0000000..bbd3781 --- /dev/null +++ b/libodb-mssql/tests/build/root.build @@ -0,0 +1,23 @@ +# file : tests/build/root.build +# license : ODB NCUEL; see accompanying LICENSE file + +cxx.std = latest + +using cxx + +hxx{*}: extension = hxx +cxx{*}: extension = cxx + +if ($cxx.target.system == 'win32-msvc') + cxx.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS + +if ($cxx.class == 'msvc') + cxx.coptions += /wd4251 /wd4275 /wd4800 + +# Every exe{} in this subproject is by default a test. +# +exe{*}: test = true + +# Specify the test target for cross-testing. +# +test.target = $cxx.target diff --git a/libodb-mssql/tests/buildfile b/libodb-mssql/tests/buildfile new file mode 100644 index 0000000..fd73adc --- /dev/null +++ b/libodb-mssql/tests/buildfile @@ -0,0 +1,4 @@ +# file : tests/buildfile +# license : ODB NCUEL; see accompanying LICENSE file + +./: {*/ -build/} diff --git a/m4/acx-pthread.m4 b/m4/acx-pthread.m4 deleted file mode 100644 index 204b32d..0000000 --- a/m4/acx-pthread.m4 +++ /dev/null @@ -1,259 +0,0 @@ -dnl -dnl NOTE: This file was modified. See the comments starting with 'CS:' -dnl for more information. In particular, it was changed to use C++ -dnl instead of C. -dnl -dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -dnl -dnl @summary figure out how to build C++ programs using POSIX threads -dnl -dnl This macro figures out how to build C++ programs using POSIX threads. -dnl It sets the PTHREAD_LIBS output variable to the threads library and -dnl linker flags, and the PTHREAD_CXXFLAGS output variable to any special -dnl C++ compiler flags that are needed. (The user can also force certain -dnl compiler flags/libs to be tested by setting these environment -dnl variables.) -dnl -dnl Also sets PTHREAD_CXX to any special C++ compiler that is needed for -dnl multi-threaded programs (defaults to the value of CXX otherwise). -dnl (This is necessary on AIX to use the special xlC_r compiler alias.) -dnl -dnl NOTE: You are assumed to not only compile your program with these -dnl flags, but also link it with them as well. e.g. you should link -dnl with $PTHREAD_CXX $CXXFLAGS $PTHREAD_CXXFLAGS $LDFLAGS ... $PTHREAD_LIBS -dnl $LIBS -dnl -dnl If you are only building threads programs, you may wish to use -dnl these variables in your default LIBS, CXXFLAGS, and CXX: -dnl -dnl LIBS="$PTHREAD_LIBS $LIBS" -dnl CXXFLAGS="$CXXFLAGS $PTHREAD_CXXFLAGS" -dnl CXX="$PTHREAD_CXX" -dnl -dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute -dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to -dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). -dnl -dnl ACTION-IF-FOUND is a list of shell commands to run if a threads -dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to -dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the -dnl default action will define HAVE_PTHREAD. -dnl -dnl Please let the authors know if this macro fails on any platform, or -dnl if you have any other suggestions or comments. This macro was based -dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with -dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros -dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. -dnl We are also grateful for the helpful feedback of numerous users. -dnl -dnl @category InstalledPackages -dnl @author Steven G. Johnson -dnl @version 2006-05-29 -dnl @license GPLWithACException - -AC_DEFUN([ACX_PTHREAD], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_LANG_SAVE -AC_LANG(C++) -acx_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test x"$PTHREAD_LIBS$PTHREAD_CXXFLAGS" != x; then - save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $PTHREAD_CXXFLAGS" - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CXXFLAGS=$PTHREAD_CXXFLAGS]) - AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) - AC_MSG_RESULT($acx_pthread_ok) - if test x"$acx_pthread_ok" = xno; then - PTHREAD_LIBS="" - PTHREAD_CXXFLAGS="" - fi - LIBS="$save_LIBS" - CXXFLAGS="$save_CXXFLAGS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all, and "pthread-config" -# which is a program returning the flags for the Pth emulation library. - -# CS: On GNU/Linux with gcc both -pthread and -lpthread are valid. -# However, libtool links libraries with -nostdlib which results in -# -pthread being stripped from the linker command line. To resolve -# this we move pthread from after -mthreads to after pthreads. -# -acx_pthread_flags="pthreads pthread none -Kthread -kthread lthread -pthread -pthreads -mthreads --thread-safe -mt pthread-config" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC -# pthread: Linux, etcetera -# --thread-safe: KAI C++ -# pthread-config: use pthread-config program (for GNU Pth library) - -case "${host_cpu}-${host_os}" in - *solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: - - # CS: Move -mt to the front of the list; Sun CC will use -mt, - # gcc will use -pthreads. - # - acx_pthread_flags="-mt -pthreads pthread -pthread $acx_pthread_flags" - ;; -esac - -if test x"$acx_pthread_ok" = xno; then -for flag in $acx_pthread_flags; do - - case $flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CXXFLAGS="$flag" - ;; - - pthread-config) - AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) - if test x"$acx_pthread_config" = xno; then continue; fi - PTHREAD_CXXFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" - ;; - esac - - save_LIBS="$LIBS" - save_CXXFLAGS="$CXXFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - CXXFLAGS="$CXXFLAGS $PTHREAD_CXXFLAGS" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - # - AC_TRY_LINK([#include ], - [pthread_t th; pthread_join(th, 0); - pthread_attr_init(0); pthread_cleanup_push(0, 0); - pthread_create(0,0,0,0); pthread_cleanup_pop(0);], - [acx_pthread_ok=yes]) - - LIBS="$save_LIBS" - CXXFLAGS="$save_CXXFLAGS" - - AC_MSG_RESULT($acx_pthread_ok) - if test "x$acx_pthread_ok" = xyes; then - break; - fi - - PTHREAD_LIBS="" - PTHREAD_CXXFLAGS="" -done -fi - -# Various other checks: -if test "x$acx_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $PTHREAD_CXXFLAGS" - -dnl # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. -dnl AC_MSG_CHECKING([for joinable pthread attribute]) -dnl attr_name=unknown -dnl for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do -dnl AC_TRY_LINK([#include ], [int attr=$attr; return attr;], -dnl [attr_name=$attr; break]) -dnl done -dnl AC_MSG_RESULT($attr_name) -dnl if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then -dnl AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, -dnl [Define to necessary symbol if this constant -dnl uses a non-standard name on your system.]) -dnl fi - - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case "${host_cpu}-${host_os}" in - *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; - # CS: Add _REENTRANT in Linux to emulate -pthread. - # - *-linux* | *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; - esac - AC_MSG_RESULT(${flag}) - if test "x$flag" != xno; then - PTHREAD_CXXFLAGS="$flag $PTHREAD_CXXFLAGS" - fi - - LIBS="$save_LIBS" - CXXFLAGS="$save_CXXFLAGS" - -dnl # More AIX lossage: must compile with xlC_r -dnl if test x"$GXX" != xyes; then -dnl AC_CHECK_PROGS(PTHREAD_CXX, xlC_r, ${CXX}) -dnl else -dnl PTHREAD_CXX=$CXX -dnl fi - -else - PTHREAD_CXX="$CXX" -fi - -AC_SUBST(PTHREAD_LIBS) -AC_SUBST(PTHREAD_CXXFLAGS) -AC_SUBST(PTHREAD_CXX) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$acx_pthread_ok" = xyes; then - ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) - : -else - acx_pthread_ok=no - $2 -fi -AC_LANG_RESTORE -])dnl ACX_PTHREAD diff --git a/m4/disable-rpath.m4 b/m4/disable-rpath.m4 deleted file mode 100644 index 0864209..0000000 --- a/m4/disable-rpath.m4 +++ /dev/null @@ -1,24 +0,0 @@ -dnl file : m4/disable-rpath.m4 -dnl license : GNU GPL v2; see accompanying LICENSE file -dnl -AC_DEFUN([DISABLE_RPATH],[ - -AC_MSG_CHECKING([whether to use rpath]) -AC_ARG_ENABLE( - [rpath], - [AC_HELP_STRING([--disable-rpath], [patch libtool to not use rpath])], - [libtool_rpath="$enable_rpath"], - [libtool_rpath="yes"]) -AC_MSG_RESULT($libtool_rpath) - -# Patch libtool to not use rpath if requested. -# -AC_CONFIG_COMMANDS( - [libtool-rpath-patch], - [if test "$libtool_use_rpath" = "no"; then - sed < libtool > libtool-2 's/^hardcode_libdir_flag_spec.*$'/'hardcode_libdir_flag_spec=" -D__LIBTOOL_NO_RPATH__ "/' - mv libtool-2 libtool - chmod 755 libtool - fi], - [libtool_use_rpath=$libtool_rpath]) -])dnl diff --git a/m4/libodb.m4 b/m4/libodb.m4 deleted file mode 100644 index 0dba7c4..0000000 --- a/m4/libodb.m4 +++ /dev/null @@ -1,81 +0,0 @@ -dnl file : m4/libodb.m4 -dnl license : GNU GPL v2; see accompanying LICENSE file -dnl -dnl LIBODB([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -dnl -dnl -AC_DEFUN([LIBODB], [ -libodb_found=no - -AC_ARG_WITH( - [libodb], - [AC_HELP_STRING([--with-libodb=DIR],[location of libodb build directory])], - [libodb_dir=${withval}], - [libodb_dir=]) - -AC_MSG_CHECKING([for libodb]) - -# If libodb_dir was given, add the necessary preprocessor and linker flags. -# -if test x"$libodb_dir" != x; then - save_CPPFLAGS="$CPPFLAGS" - save_LDFLAGS="$LDFLAGS" - - AS_SET_CATFILE([abs_libodb_dir], [$ac_pwd], [$libodb_dir]) - - CPPFLAGS="$CPPFLAGS -I$abs_libodb_dir" - LDFLAGS="$LDFLAGS -L$abs_libodb_dir/odb" -fi - -save_LIBS="$LIBS" -LIBS="-lodb $LIBS" - -CXX_LIBTOOL_LINK_IFELSE([ -AC_LANG_SOURCE([ -#include - -void -f () -{ -} - -const char* -g () -{ - try - { - f (); - } - catch (const odb::exception& e) - { - return e.what (); - } - return 0; -} - -int -main () -{ - const char* m (g ()); - return m != 0; -} -])], -[libodb_found=yes]) - -if test x"$libodb_found" = xno; then - LIBS="$save_LIBS" - - if test x"$libodb_dir" != x; then - CPPFLAGS="$save_CPPFLAGS" - LDFLAGS="$save_LDFLAGS" - fi -fi - -if test x"$libodb_found" = xyes; then - AC_MSG_RESULT([yes]) - $1 -else - AC_MSG_RESULT([no]) - $2 -fi -])dnl diff --git a/m4/libodbc.m4 b/m4/libodbc.m4 deleted file mode 100644 index 50a36be..0000000 --- a/m4/libodbc.m4 +++ /dev/null @@ -1,70 +0,0 @@ -dnl file : m4/libodbc.m4 -dnl license : GNU GPL v2; see accompanying LICENSE file -dnl -dnl LIBODBC([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]) -dnl -AC_DEFUN([LIBODBC], [ -libodbc_found=no - -AC_MSG_CHECKING([for libodbc]) - -save_LIBS="$LIBS" - -case $host_os in - mingw*) - LIBS="-lodbc32 $LIBS" - ;; - *) - LIBS="-lodbc $LIBS" - ;; -esac - -CXX_LIBTOOL_LINK_IFELSE([ -AC_LANG_SOURCE([ -#ifdef _WIN32 -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -#endif - -#include - -int -main () -{ - SQLHENV env; - SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); - - SQLHDBC conn; - SQLAllocHandle (SQL_HANDLE_DBC, env, &conn); - SQLDriverConnectA (conn, - 0, - (SQLCHAR*) "example.com", - SQL_NTS, - 0, - 0, - 0, - SQL_DRIVER_NOPROMPT); - - SQLHSTMT stmt; - SQLAllocHandle (SQL_HANDLE_STMT, conn, &stmt); - SQLPrepareA (stmt, (SQLCHAR*) "SELECT 1", SQL_NTS); -} -])], -[ -libodbc_found=yes -]) - -if test x"$libodbc_found" = xno; then - LIBS="$save_LIBS" -fi - -if test x"$libodbc_found" = xyes; then - AC_MSG_RESULT([yes]) - $1 -else - AC_MSG_RESULT([no]) - $2 -fi -])dnl diff --git a/m4/libtool-link.m4 b/m4/libtool-link.m4 deleted file mode 100644 index 302639f..0000000 --- a/m4/libtool-link.m4 +++ /dev/null @@ -1,45 +0,0 @@ -dnl file : m4/libtool-link.m4 -dnl license : GNU GPL v2; see accompanying LICENSE file -dnl -dnl -dnl CXX_LIBTOOL_LINK_IFELSE (input, [action-if-true], [action-if-false]) -dnl -dnl Similar to AC_LINK_IFELSE except it uses libtool to perform the -dnl linking and it does this using the C++ compiler. -dnl -AC_DEFUN([CXX_LIBTOOL_LINK_IFELSE],[ -AC_LANG_SAVE -AC_LANG(C++) - -if test -d .libs; then - delete_libs_dir=no -else - delete_libs_dir=yes -fi - -AC_COMPILE_IFELSE([$1], -[ - ac_try='./libtool --tag=CXX --mode=link $CXX -no-install $CXXFLAGS $LDFLAGS -o conftest conftest.$OBJEXT $LIBS >&AS_MESSAGE_LOG_FD' - if _AC_DO_VAR(ac_try); then - libtool_link_ok=yes - else - libtool_link_ok=no - fi -], -[ - libtool_link_ok=no -]) - -if test x"$delete_libs_dir" = xyes; then - rm -rf .libs -fi - -if test x"$libtool_link_ok" = xyes; then -[$2] -: -else -[$3] -: -fi - -AC_LANG_RESTORE])dnl diff --git a/m4/pkgconfig.m4 b/m4/pkgconfig.m4 deleted file mode 100644 index c48ea56..0000000 --- a/m4/pkgconfig.m4 +++ /dev/null @@ -1,11 +0,0 @@ -dnl file : m4/pkgconfig.m4 -dnl license : GNU GPL v2; see accompanying LICENSE file -dnl -AC_DEFUN([PKGCONFIG],[ -AC_ARG_WITH( - [pkgconfigdir], - [AC_HELP_STRING([--with-pkgconfigdir=DIR],[location of pkgconfig dir (default is libdir/pkgconfig)])], - [pkgconfigdir=${withval}], - [pkgconfigdir='${libdir}/pkgconfig']) -AC_SUBST([pkgconfigdir]) -])dnl diff --git a/m4/static-lib.m4 b/m4/static-lib.m4 deleted file mode 100644 index 5fb1c11..0000000 --- a/m4/static-lib.m4 +++ /dev/null @@ -1,17 +0,0 @@ -dnl file : m4/static-lib.m4 -dnl license : GNU GPL v2; see accompanying LICENSE file -dnl -dnl STATIC_LIB(MACRO, DESCRIPTION) -dnl -dnl Define MACRO if we are on MinGW and are only building static library. -dnl -AC_DEFUN([STATIC_LIB], -[ -if test x$enable_shared = xno; then - case $host_os in - mingw*) - AC_DEFINE([$1], [1], [$2]) - ;; - esac -fi -])dnl diff --git a/m4/threads.m4 b/m4/threads.m4 deleted file mode 100644 index 6f2e25f..0000000 --- a/m4/threads.m4 +++ /dev/null @@ -1,68 +0,0 @@ -dnl file : m4/threads.m4 -dnl license : GNU GPL v2; see accompanying LICENSE file -dnl -AC_DEFUN([THREADS],[ - -threads_thread_keyword=no - -AC_ARG_ENABLE( - [threads], - AS_HELP_STRING([--disable-threads], [disable threads (enabled by default)]), - [AS_IF([test x"$enableval" = xno], [threads=none], [threads=check])], - [threads=check]) - -# If thread support is not disabled by the user, figure out what we can use. -# -if test x$threads = xcheck; then - case $host_os in - windows* | mingw*) - case $host_os in - mingw*) - CXXFLAGS="$CXXFLAGS -mthreads" - ;; - esac - - # Newer versions of GCC can be configured to use either Win32 or POSIX - # threads. It appears that -mthreads should be used in both cases but - # if the model is POSIX then GCC will also link -lpthread by default. - # Use that fact to test which model we have. - # - AC_TRY_LINK([#include ], - [pthread_create(0,0,0,0);], - [threads=posix], - [threads=win32]) - ;; - *) - ACX_PTHREAD - - if test x$acx_pthread_ok = xyes; then - threads=posix - LIBS="$LIBS $PTHREAD_LIBS" - CXXFLAGS="$CXXFLAGS $PTHREAD_CXXFLAGS" - - # Check if we can use the __thread keyword. - # - AC_MSG_CHECKING([for __thread keyword]) - - CXX_LIBTOOL_LINK_IFELSE([ - AC_LANG_SOURCE([ - __thread int tls_var; - - int - main () - { - tls_var = 0; - } - ])], - [threads_thread_keyword=yes]) - - AC_MSG_RESULT([$threads_thread_keyword]) - fi - ;; - esac -fi - -if test x$threads = xcheck; then - AC_MSG_ERROR([thread support not available; use --disable-threads to force single-threaded mode]) -fi -])dnl diff --git a/makefile b/makefile deleted file mode 100644 index c03ca78..0000000 --- a/makefile +++ /dev/null @@ -1,35 +0,0 @@ -# file : makefile -# license : ODB NCUEL; see accompanying LICENSE file - -include $(dir $(lastword $(MAKEFILE_LIST)))build/bootstrap.make - -dirs := odb/mssql - -default := $(out_base)/ -dist := $(out_base)/.dist -clean := $(out_base)/.clean - -$(default): $(addprefix $(out_base)/,$(addsuffix /,$(dirs))) - -$(dist): export dirs := $(dirs) -$(dist): export docs := NCUEL LICENSE README NEWS version.txt -$(dist): data_dist := INSTALL libodb-mssql-vc8.sln libodb-mssql-vc9.sln \ -libodb-mssql-vc10.sln libodb-mssql-vc11.sln libodb-mssql-vc12.sln -$(dist): exec_dist := bootstrap -$(dist): export extra_dist := $(data_dist) $(exec_dist) -$(dist): export version = $(shell cat $(src_root)/version.txt) - -$(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(dirs))) - $(call dist-data,$(docs) $(data_dist) libodb-mssql.pc.in) - $(call dist-exec,$(exec_dist)) - $(call dist-dir,m4) - $(call meta-automake) - $(call meta-autoconf) - -$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(dirs))) - -$(call include,$(bld_root)/dist.make) -$(call include,$(bld_root)/meta/automake.make) -$(call include,$(bld_root)/meta/autoconf.make) - -$(foreach d,$(dirs),$(call import,$(src_base)/$d/makefile)) diff --git a/manifest b/manifest deleted file mode 100644 index 68e5a84..0000000 --- a/manifest +++ /dev/null @@ -1,23 +0,0 @@ -: 1 -name: libodb-mssql -version: 2.5.0-b.26.z -project: odb -summary: Microsoft SQL Server ODB runtime library -license: other: ODB NCUEL ; Non-Commercial Use and Evaluation License. -license: other: proprietary ; Not free/open source. -topics: C++, ORM, Microsoft SQL Server, SQL -description-file: README -changes-file: NEWS -url: https://www.codesynthesis.com/products/odb/ -doc-url: https://www.codesynthesis.com/products/odb/doc/manual.xhtml -src-url: https://git.codesynthesis.com/cgit/odb/libodb-mssql/ -email: odb-users@codesynthesis.com -build-warning-email: odb-builds@codesynthesis.com -builds: windows ; Requires not yet packaged libunixodbc (unixODBC). -requires: c++11 -# @@ DEP -#requires: ? libunixodbc ; Only on UNIX. -depends: * build2 >= 0.16.0- -depends: * bpkg >= 0.16.0- -depends: libodb [2.5.0-b.26.1 2.5.0-b.27) -depends: * cli ^1.2.0- ? ($config.libodb_mssql.develop) diff --git a/odb/mssql/Makefile.am b/odb/mssql/Makefile.am deleted file mode 100644 index 85c949d..0000000 --- a/odb/mssql/Makefile.am +++ /dev/null @@ -1,14 +0,0 @@ -# file : odb/mssql/Makefile.am -# license : ODB NCUEL; see accompanying LICENSE file - -lib_LTLIBRARIES = libodb-mssql.la -libodb_mssql_la_SOURCES = __path__(sources) - -odbmssqlincludedir = $(includedir)/odb/mssql/ -nobase_odbmssqlinclude_HEADERS = __path__(headers) -nobase_nodist_odbmssqlinclude_HEADERS = details/config.h - -EXTRA_DIST = __file__(extra_dist) - -AM_CPPFLAGS= -I'$(top_builddir)' -I'$(top_srcdir)' -DLIBODB_MSSQL_DYNAMIC_LIB -AM_LDFLAGS = -release __value__(interface_version) -no-undefined diff --git a/odb/mssql/auto-handle.cxx b/odb/mssql/auto-handle.cxx deleted file mode 100644 index ca42040..0000000 --- a/odb/mssql/auto-handle.cxx +++ /dev/null @@ -1,17 +0,0 @@ -// file : odb/mssql/auto-handle.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include -#include - -namespace odb -{ - namespace mssql - { - void - free_handle (SQLHANDLE h, SQLSMALLINT htype) - { - SQLFreeHandle (htype, h); - } - } -} diff --git a/odb/mssql/auto-handle.hxx b/odb/mssql/auto-handle.hxx deleted file mode 100644 index f6934e4..0000000 --- a/odb/mssql/auto-handle.hxx +++ /dev/null @@ -1,88 +0,0 @@ -// file : odb/mssql/auto-handle.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_AUTO_HANDLE_HXX -#define ODB_MSSQL_AUTO_HANDLE_HXX - -#include - -#include // ODB_CXX11 - -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - LIBODB_MSSQL_EXPORT void - free_handle (SQLHANDLE, SQLSMALLINT htype); - - template - class auto_handle - { - public: - auto_handle (SQLHANDLE h = 0) - : h_ (h) - { - } - - ~auto_handle () - { - if (h_ != 0) - free_handle (h_, htype); - } - - operator SQLHANDLE () const - { - return h_; - } - - SQLHANDLE - get () const - { - return h_; - } - - SQLHANDLE - release () - { - SQLHANDLE h (h_); - h_ = 0; - return h; - } - - void - reset (SQLHANDLE h = 0) - { - if (h_ != 0) - free_handle (h_, htype); - - h_ = h; - } - -#ifdef ODB_CXX11 - auto_handle (auto_handle&& ah) noexcept: h_ (ah.release ()) {} - auto_handle& operator= (auto_handle&& ah) noexcept - { - if (this != &ah) - reset (ah.release ()); - return *this; - } -#endif - - private: - auto_handle (const auto_handle&); - auto_handle& operator= (const auto_handle&); - - private: - SQLHANDLE h_; - }; - } -} - -#include - -#endif // ODB_MSSQL_AUTO_HANDLE_HXX diff --git a/odb/mssql/binding.hxx b/odb/mssql/binding.hxx deleted file mode 100644 index c7d1bd8..0000000 --- a/odb/mssql/binding.hxx +++ /dev/null @@ -1,65 +0,0 @@ -// file : odb/mssql/binding.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_BINDING_HXX -#define ODB_MSSQL_BINDING_HXX - -#include - -#include // std::size_t - -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - class LIBODB_MSSQL_EXPORT binding - { - public: - typedef mssql::bind bind_type; - typedef mssql::change_callback change_callback_type; - - binding () - : bind (0), count (0), version (0), - batch (0), skip (0), status (0), - change_callback (0) {} - - binding (bind_type* b, std::size_t n) - : bind (b), count (n), version (0), - batch (1), skip (0), status (0), - change_callback (0) - { - } - - binding (bind_type* b, std::size_t n, - std::size_t bt, std::size_t s, SQLUSMALLINT* st) - : bind (b), count (n), version (0), - batch (bt), skip (s), status (st), - change_callback (0) - { - } - - bind_type* bind; - std::size_t count; - std::size_t version; - - std::size_t batch; - std::size_t skip; - SQLUSMALLINT* status; // Batch status array. - - change_callback_type* change_callback; - - private: - binding (const binding&); - binding& operator= (const binding&); - }; - } -} - -#include - -#endif // ODB_MSSQL_BINDING_HXX diff --git a/odb/mssql/buildfile b/odb/mssql/buildfile deleted file mode 100644 index 5a99ebc..0000000 --- a/odb/mssql/buildfile +++ /dev/null @@ -1,165 +0,0 @@ -# file : odb/mssql/buildfile -# license : ODB NCUEL; see accompanying LICENSE file - -define cli: file -cli{*}: extension = cli - -import int_libs = libodb%lib{odb} - -# On Windows ODBC is a pre-installed system library so we pass it to the -# linker directly -# -imp_libs = - -if ($cc.target.class != 'windows') - import imp_libs = libunixodbc%lib{odbc} - -lib{odb-mssql}: {hxx ixx txx cxx}{* -version-build2} {hxx}{version-build2} \ - details/{hxx ixx txx cxx}{* -options} \ - details/build2/{h}{*} \ - $imp_libs $int_libs - -# Include the generated version header into the distribution (so that we don't -# pick up an installed one) and don't remove it when cleaning in src (so that -# clean results in a state identical to distributed). -# -hxx{version-build2}: in{version-build2} $src_root/manifest -hxx{version-build2}: -{ - dist = true - clean = ($src_root != $out_root) -} - -# Build options. -# -cxx.poptions =+ "-I$out_root" "-I$src_root" -DLIBODB_MSSQL_BUILD2 - -obja{*}: cxx.poptions += -DLIBODB_MSSQL_STATIC_BUILD -objs{*}: cxx.poptions += -DLIBODB_MSSQL_SHARED_BUILD - -if ($cc.target.class == 'windows') - cxx.libs += ($cxx.target.system == "mingw32" ? -lodbc32 : odbc32.lib) - -# Export options. -# -lib{odb-mssql}: -{ - cxx.export.poptions = "-I$out_root" "-I$src_root" -DLIBODB_MSSQL_BUILD2 - cxx.export.libs = $int_libs -} - -liba{odb-mssql}: cxx.export.poptions += -DLIBODB_MSSQL_STATIC -libs{odb-mssql}: cxx.export.poptions += -DLIBODB_MSSQL_SHARED - -# For pre-releases use the complete version to make sure they cannot be used -# in place of another pre-release or the final version. See the version module -# for details on the version.* variable values. -# -if $version.pre_release - lib{odb-mssql}: bin.lib.version = @"-$version.project_id" -else - lib{odb-mssql}: bin.lib.version = @"-$version.major.$version.minor" - -develop = $config.libodb_mssql.develop - -## Consumption build ($develop == false). -# - -# Use pregenerated versions in the consumption build. -# -lib{odb-mssql}: details/pregenerated/{hxx ixx cxx}{**}: include = (!$develop) - -if! $develop - cxx.poptions =+ "-I($src_base/details/pregenerated)" # Note: must come first. - -# Don't install pregenerated headers since they are only used internally in -# the database implementation (also below). -# -details/pregenerated/{hxx ixx}{*}: install = false - -# Distribute pregenerated versions only in the consumption build. -# -details/pregenerated/{hxx ixx cxx}{*}: dist = (!$develop) - -# -## - -## Development build ($develop == true). -# - -lib{odb-mssql}: details/{hxx ixx cxx}{options}: include = $develop - -if $develop - import! [metadata] cli = cli%exe{cli} - -# In the development build distribute regenerated {hxx ixx cxx}{options}, -# remapping their locations to the paths of the pregenerated versions (which -# are only distributed in the consumption build; see above). This way we make -# sure that the distributed files are always up-to-date. -# -
: details/cli{options} $cli -{ - install = false - dist = ($develop ? pregenerated/odb/mssql/details/ : false) - - # Symlink the generated code in src for convenience of development. - # - backlink = true -} -% -if $develop -{{ - options = --include-with-brackets --include-prefix odb/mssql/details \ - --guard-prefix LIBODB_MSSQL_DETAILS --generate-file-scanner \ - --cli-namespace odb::mssql::details::cli --long-usage \ - --generate-specifier --no-combined-flags - - $cli $options -o $out_base/details/ $path($<[0]) - - # If the result differs from the pregenerated version, copy it over. - # - d = [dir_path] $src_base/details/pregenerated/odb/mssql/details/ - - if diff $d/options.hxx $path($>[0]) >- && \ - diff $d/options.ixx $path($>[1]) >- && \ - diff $d/options.cxx $path($>[2]) >- - exit - end - - cp $path($>[0]) $d/options.hxx - cp $path($>[1]) $d/options.ixx - cp $path($>[2]) $d/options.cxx -}} - -# Install into the odb/mssql/ subdirectory of, say, /usr/include/ -# recreating subdirectories. -# -install_include = [dir_path] include/odb/mssql/ - -{hxx ixx txx}{*}: -{ - install = $install_include - install.subdirs = true -} - -# We want these to be picked up whether LIBODB_MSSQL_BUILD2 is defined or not. -# -hxx{version}@./: install = false -hxx{version-build2}: install = $install_include/version.hxx -hxx{version-build2-stub}@./: install = $install_include/version-build2.hxx - -details/build2/ -{ - h{*}: install = false - - if ($cxx.target.system == 'win32-msvc') - { - h{config-vc}@./: install = $install_include/details/ - h{config-vc-stub}@./: install = $install_include/details/build2/config-vc.h - } - else - { - h{config}@./: install = $install_include/details/ - h{config-stub}@./: install = $install_include/details/build2/config.h - } -} diff --git a/odb/mssql/connection-factory.cxx b/odb/mssql/connection-factory.cxx deleted file mode 100644 index f673b92..0000000 --- a/odb/mssql/connection-factory.cxx +++ /dev/null @@ -1,159 +0,0 @@ -// file : odb/mssql/connection-factory.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include -#include - -#include - -using namespace std; - -namespace odb -{ - using namespace details; - - namespace mssql - { - // new_connection_factory - // - connection_ptr new_connection_factory:: - connect () - { - return connection_ptr (new (shared) connection (*this)); - } - - // connection_pool_factory - // - connection_pool_factory::pooled_connection_ptr connection_pool_factory:: - create () - { - return pooled_connection_ptr (new (shared) pooled_connection (*this)); - } - - connection_pool_factory:: - ~connection_pool_factory () - { - // Wait for all the connections currently in use to return to - // the pool. - // - lock l (mutex_); - while (in_use_ != 0) - { - waiters_++; - cond_.wait (l); - waiters_--; - } - } - - connection_ptr connection_pool_factory:: - connect () - { - lock l (mutex_); - - while (true) - { - // See if we have a spare connection. - // - if (connections_.size () != 0) - { - shared_ptr c (connections_.back ()); - connections_.pop_back (); - - c->callback_ = &c->cb_; - in_use_++; - return c; - } - - // See if we can create a new one. - // - if (max_ == 0 || in_use_ < max_) - { - shared_ptr c (create ()); - c->callback_ = &c->cb_; - in_use_++; - return c; - } - - // Wait until someone releases a connection. - // - waiters_++; - cond_.wait (l); - waiters_--; - } - } - - void connection_pool_factory:: - database (database_type& db) - { - bool first (db_ == 0); - - connection_factory::database (db); - - if (!first) - return; - - if (min_ > 0) - { - connections_.reserve (min_); - - for(size_t i (0); i < min_; ++i) - connections_.push_back (create ()); - } - } - - bool connection_pool_factory:: - release (pooled_connection* c) - { - c->callback_ = 0; - - lock l (mutex_); - - // Determine if we need to keep or free this connection. - // - bool keep (!c->failed () && - (waiters_ != 0 || - min_ == 0 || - (connections_.size () + in_use_ <= min_))); - - in_use_--; - - if (keep) - { - connections_.push_back (pooled_connection_ptr (inc_ref (c))); - connections_.back ()->recycle (); - } - - if (waiters_ != 0) - cond_.signal (); - - return !keep; - } - - // - // connection_pool_factory::pooled_connection - // - - connection_pool_factory::pooled_connection:: - pooled_connection (connection_pool_factory& f) - : connection (f) - { - cb_.arg = this; - cb_.zero_counter = &zero_counter; - } - - connection_pool_factory::pooled_connection:: - pooled_connection (connection_pool_factory& f, SQLHDBC handle) - : connection (f, handle) - { - cb_.arg = this; - cb_.zero_counter = &zero_counter; - } - - bool connection_pool_factory::pooled_connection:: - zero_counter (void* arg) - { - pooled_connection* c (static_cast (arg)); - return static_cast (c->factory_).release (c); - } - } -} diff --git a/odb/mssql/connection-factory.hxx b/odb/mssql/connection-factory.hxx deleted file mode 100644 index 14861a5..0000000 --- a/odb/mssql/connection-factory.hxx +++ /dev/null @@ -1,134 +0,0 @@ -// file : odb/mssql/connection-factory.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_CONNECTION_FACTORY_HXX -#define ODB_MSSQL_CONNECTION_FACTORY_HXX - -#include - -#include -#include // std::size_t -#include - -#include -#include -#include - -#include -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - class LIBODB_MSSQL_EXPORT new_connection_factory: public connection_factory - { - public: - new_connection_factory () {} - - virtual connection_ptr - connect (); - - private: - new_connection_factory (const new_connection_factory&); - new_connection_factory& operator= (const new_connection_factory&); - }; - - class LIBODB_MSSQL_EXPORT connection_pool_factory: - public connection_factory - { - public: - // The max_connections argument specifies the maximum number of - // concurrent connections this pool will maintain. If this value - // is 0 then the pool will create a new connection every time all - // of the existing connections are in use. - // - // The min_connections argument specifies the minimum number of - // connections that should be maintained by the pool. If the - // number of connections maintained by the pool exceeds this - // number and there are no active waiters for a new connection, - // then the pool will release the excess connections. If this - // value is 0 then the pool will maintain all the connections - // that were ever created. - // - connection_pool_factory (std::size_t max_connections = 0, - std::size_t min_connections = 0) - : max_ (max_connections), - min_ (min_connections), - in_use_ (0), - waiters_ (0), - cond_ (mutex_) - { - // max_connections == 0 means unlimited. - // - assert (max_connections == 0 || max_connections >= min_connections); - } - - virtual connection_ptr - connect (); - - virtual void - database (database_type&); - - virtual - ~connection_pool_factory (); - - private: - connection_pool_factory (const connection_pool_factory&); - connection_pool_factory& operator= (const connection_pool_factory&); - - protected: - class LIBODB_MSSQL_EXPORT pooled_connection: public connection - { - public: - pooled_connection (connection_pool_factory&); - pooled_connection (connection_pool_factory&, SQLHDBC); - - private: - static bool - zero_counter (void*); - - private: - friend class connection_pool_factory; - - shared_base::refcount_callback cb_; - }; - - friend class pooled_connection; - - typedef details::shared_ptr pooled_connection_ptr; - typedef std::vector connections; - - // This function is called whenever the pool needs to create a new - // connection. - // - virtual pooled_connection_ptr - create (); - - protected: - // Return true if the connection should be deleted, false otherwise. - // - bool - release (pooled_connection*); - - protected: - const std::size_t max_; - const std::size_t min_; - - std::size_t in_use_; // Number of connections currently in use. - std::size_t waiters_; // Number of threads waiting for a connection. - - connections connections_; - - details::mutex mutex_; - details::condition cond_; - }; - } -} - -#include - -#endif // ODB_MSSQL_CONNECTION_FACTORY_HXX diff --git a/odb/mssql/connection.cxx b/odb/mssql/connection.cxx deleted file mode 100644 index 5181fab..0000000 --- a/odb/mssql/connection.cxx +++ /dev/null @@ -1,287 +0,0 @@ -// file : odb/mssql/connection.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include -#include //intptr_t - -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -namespace odb -{ - namespace mssql - { - static const intptr_t transaction_isolation_map[] = - { - SQL_TXN_READ_UNCOMMITTED, - SQL_TXN_READ_COMMITTED, - SQL_TXN_REPEATABLE_READ, - SQL_TXN_SS_SNAPSHOT, - SQL_TXN_SERIALIZABLE - }; - - connection:: - connection (connection_factory& cf) - : odb::connection (cf), - state_ (state_disconnected), - statement_cache_ (new statement_cache_type (*this)), - long_data_buffer_ (0) - { - SQLRETURN r; - - database_type& db (database ()); - - // Allocate the connection handle. - // - { - SQLHANDLE h; - r = SQLAllocHandle (SQL_HANDLE_DBC, db.environment (), &h); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, db.environment (), SQL_HANDLE_ENV); - - handle_.reset (h); - } - - // Set the manual commit mode. - // - r = SQLSetConnectAttrA (handle_, - SQL_ATTR_AUTOCOMMIT, - (SQLPOINTER) SQL_AUTOCOMMIT_OFF, - 0); - - if (!SQL_SUCCEEDED (r)) - // Still use the handle version of translate_error since there - // is no connection yet. - // - translate_error (r, handle_, SQL_HANDLE_DBC); - - // Enable Multiple Active Result Sets (MARS). - // - r = SQLSetConnectAttrA (handle_, - SQL_COPT_SS_MARS_ENABLED, - (SQLPOINTER) SQL_MARS_ENABLED_YES, - SQL_IS_UINTEGER); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, handle_, SQL_HANDLE_DBC); - - // Set transaction isolation level. - // - transaction_isolation ti (db.transaction_isolation ()); - switch (ti) - { - case isolation_read_committed: - { - break; // SQL Server default. - } - case isolation_read_uncommitted: - case isolation_repeatable_read: - case isolation_serializable: - { - r = SQLSetConnectAttrA (handle_, - SQL_ATTR_TXN_ISOLATION, - (SQLPOINTER) transaction_isolation_map[ti], - 0); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, handle_, SQL_HANDLE_DBC); - break; - } - case isolation_snapshot: - { - r = SQLSetConnectAttrA (handle_, - SQL_COPT_SS_TXN_ISOLATION, - (SQLPOINTER) transaction_isolation_map[ti], - SQL_IS_INTEGER); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, handle_, SQL_HANDLE_DBC); - break; - } - } - - // Connect. - // - { - SQLSMALLINT out_conn_str_size; - r = SQLDriverConnectA (handle_, - 0, // Parent window handle. - (SQLCHAR*) db.connect_string ().c_str (), - SQL_NTS, - 0, // Output connection string buffer. - 0, // Size of output connection string buffer. - &out_conn_str_size, - SQL_DRIVER_NOPROMPT); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, handle_, SQL_HANDLE_DBC); - - state_ = state_connected; - } - - // If an exception is thrown after this line, we will not disconnect - // the connection. - // - } - - connection:: - connection (connection_factory& cf, SQLHDBC handle) - : odb::connection (cf), - handle_ (handle), - state_ (state_connected), - statement_cache_ (new statement_cache_type (*this)), - long_data_buffer_ (0) - { - } - - connection:: - ~connection () - { - // Deallocate prepared statements before we close the connection. - // - recycle (); - clear_prepared_map (); - statement_cache_.reset (); - direct_stmt_.reset (); - - if (state_ != state_disconnected) - SQLDisconnect (handle_); // Ignore any errors. - } - - transaction_impl* connection:: - begin () - { - return new transaction_impl (connection_ptr (inc_ref (this))); - } - - unsigned long long connection:: - execute (const char* s, std::size_t n) - { - { - odb::tracer* t; - if ((t = transaction_tracer ()) || - (t = tracer ()) || - (t = database ().tracer ())) - { - string str (s, n); - t->execute (*this, str.c_str ()); - } - } - - SQLRETURN r; - - // Allocate the statement if necessary. - // - if (direct_stmt_ == 0) - { - SQLHANDLE h; - r = SQLAllocHandle (SQL_HANDLE_STMT, handle_, &h); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, *this); - - direct_stmt_.reset (h); - - // Disable escape sequences. - // - r = SQLSetStmtAttr (direct_stmt_, - SQL_ATTR_NOSCAN, - (SQLPOINTER) SQL_NOSCAN_OFF, - 0); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, *this, direct_stmt_); - - // Disable data retrieval for SELECT statements. - // - r = SQLSetStmtAttr (direct_stmt_, - SQL_ATTR_RETRIEVE_DATA, - (SQLPOINTER) SQL_RD_OFF, - 0); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, *this, direct_stmt_); - } - - // Execute. - // - r = SQLExecDirectA (direct_stmt_, (SQLCHAR*) s, (SQLINTEGER) n); - - // SQL_NO_DATA indicates that a DML statement hasn't affected - // any rows. - // - if (r == SQL_NO_DATA) - return 0; - - if (!SQL_SUCCEEDED (r)) - translate_error (r, *this, direct_stmt_); - - // Get the number of affected/returned rows. - // - SQLLEN rows; - - // See if this is a select statement. - // - SQLSMALLINT cols; - r = SQLNumResultCols (direct_stmt_, &cols); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, *this, direct_stmt_); - - if (cols != 0) - { - for (rows = 0;; ++rows) - { - r = SQLFetch (direct_stmt_); - - if (r == SQL_NO_DATA) - break; - else if (!SQL_SUCCEEDED (r)) - translate_error (r, *this, direct_stmt_); - } - - r = SQLCloseCursor (direct_stmt_); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, *this, direct_stmt_); - } - else - { - r = SQLRowCount (direct_stmt_, &rows); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, *this, direct_stmt_); - - // -1 means the row count is not available. In particular, the - // Native Client ODBC driver returns this value for DDL statements. - // - if (rows == -1) - rows = 0; - } - - return static_cast (rows); - } - - // connection_factory - // - connection_factory:: - ~connection_factory () - { - } - - void connection_factory:: - database (database_type& db) - { - odb::connection_factory::db_ = &db; - db_ = &db; - } - } -} diff --git a/odb/mssql/connection.hxx b/odb/mssql/connection.hxx deleted file mode 100644 index 204d37e..0000000 --- a/odb/mssql/connection.hxx +++ /dev/null @@ -1,187 +0,0 @@ -// file : odb/mssql/connection.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_CONNECTION_HXX -#define ODB_MSSQL_CONNECTION_HXX - -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - class statement_cache; - class connection_factory; - - class connection; - typedef details::shared_ptr connection_ptr; - - class LIBODB_MSSQL_EXPORT connection: public odb::connection - { - public: - typedef mssql::statement_cache statement_cache_type; - typedef mssql::database database_type; - - virtual - ~connection (); - - connection (connection_factory&); - connection (connection_factory&, SQLHDBC handle); - - database_type& - database (); - - public: - virtual transaction_impl* - begin (); - - public: - using odb::connection::execute; - - virtual unsigned long long - execute (const char* statement, std::size_t length); - - // Query preparation. - // - public: - template - prepared_query - prepare_query (const char* name, const char*); - - template - prepared_query - prepare_query (const char* name, const std::string&); - - template - prepared_query - prepare_query (const char* name, const mssql::query_base&); - - template - prepared_query - prepare_query (const char* name, const odb::query_base&); - - // SQL statement tracing. - // - public: - typedef mssql::tracer tracer_type; - - void - tracer (tracer_type& t) - { - odb::connection::tracer (t); - } - - void - tracer (tracer_type* t) - { - odb::connection::tracer (t); - } - - using odb::connection::tracer; - - public: - bool - failed () const - { - return state_ == state_failed; - } - - void - mark_failed () - { - state_ = state_failed; - } - - public: - SQLHDBC - handle () - { - return handle_; - } - - statement_cache_type& - statement_cache () - { - return *statement_cache_; - } - - details::buffer& - long_data_buffer () - { - return long_data_buffer_; - } - - private: - connection (const connection&); - connection& operator= (const connection&); - - private: - friend class transaction_impl; // invalidate_results() - - private: - auto_handle handle_; - - enum - { - state_disconnected, - state_connected, - state_failed - } state_; - - // Statement handle for direct execution. - // - auto_handle direct_stmt_; - details::unique_ptr statement_cache_; - details::buffer long_data_buffer_; - }; - - class LIBODB_MSSQL_EXPORT connection_factory: - public odb::connection_factory - { - public: - typedef mssql::database database_type; - - virtual void - database (database_type&); - - database_type& - database () {return *db_;} - - virtual connection_ptr - connect () = 0; - - virtual - ~connection_factory (); - - connection_factory (): db_ (0) {} - - // Needed to break the circular connection_factory-database dependency - // (odb::connection_factory has the odb::database member). - // - protected: - database_type* db_; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_CONNECTION_HXX diff --git a/odb/mssql/connection.ixx b/odb/mssql/connection.ixx deleted file mode 100644 index 8ec8294..0000000 --- a/odb/mssql/connection.ixx +++ /dev/null @@ -1,44 +0,0 @@ -// file : odb/mssql/connection.ixx -// license : ODB NCUEL; see accompanying LICENSE file - -namespace odb -{ - namespace mssql - { - inline database& connection:: - database () - { - return static_cast (factory_).database (); - } - - template - inline prepared_query connection:: - prepare_query (const char* n, const char* q) - { - return prepare_query (n, query (q)); - } - - template - inline prepared_query connection:: - prepare_query (const char* n, const std::string& q) - { - return prepare_query (n, query (q)); - } - - template - inline prepared_query connection:: - prepare_query (const char* n, const mssql::query_base& q) - { - return query_::call (*this, n, q); - } - - template - inline prepared_query connection:: - prepare_query (const char* n, const odb::query_base& q) - { - // Translate to native query. - // - return prepare_query (n, mssql::query_base (q)); - } - } -} diff --git a/odb/mssql/container-statements.hxx b/odb/mssql/container-statements.hxx deleted file mode 100644 index 16f4bf9..0000000 --- a/odb/mssql/container-statements.hxx +++ /dev/null @@ -1,353 +0,0 @@ -// file : odb/mssql/container-statements.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_CONTAINER_STATEMENTS_HXX -#define ODB_MSSQL_CONTAINER_STATEMENTS_HXX - -#include - -#include // std::size_t - -#include -#include -#include - -#include -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - class connection; - - // Template argument is the generated abstract container traits type. - // That is, it doesn't need to provide column counts and statements. - // - template - class container_statements - { - public: - typedef T traits; - - typedef typename traits::data_image_type data_image_type; - typedef typename traits::functions_type functions_type; - - typedef mssql::insert_statement insert_statement_type; - typedef mssql::select_statement select_statement_type; - typedef mssql::delete_statement delete_statement_type; - - typedef mssql::connection connection_type; - - container_statements (connection_type&, binding& id_binding); - - connection_type& - connection () - { - return conn_; - } - - // Functions. - // - functions_type& - functions () - { - return functions_; - } - - // Schema version. - // - const schema_version_migration& - version_migration () const {return *svm_;} - - void - version_migration (const schema_version_migration& svm) {svm_ = &svm;} - - // Id image binding (external). - // - const binding& - id_binding () - { - return id_binding_; - } - - // Data image. The image is split into the id (that comes as a - // binding) and index/key plus value which are in data_image_type. - // The select binding is a subset of the full binding (no id). - // - data_image_type& - data_image () - { - return data_image_; - } - - bind* - data_bind () - { - return insert_image_binding_.bind; - } - - bool - data_binding_test_version () const - { - return data_id_binding_version_ != id_binding_.version || - data_image_version_ != data_image_.version || - insert_image_binding_.version == 0; - } - - void - data_binding_update_version () - { - data_id_binding_version_ = id_binding_.version; - data_image_version_ = data_image_.version; - insert_image_binding_.version++; - select_image_binding_.version++; - } - - // - // Statements. - // - - insert_statement_type& - insert_statement () - { - if (insert_ == 0) - insert_.reset ( - new (details::shared) insert_statement_type ( - conn_, - insert_text_, - versioned_, // Process if versioned. - insert_image_binding_, - false, - false, - 0, - false)); - - return *insert_; - } - - select_statement_type& - select_statement () - { - if (select_ == 0) - select_.reset ( - new (details::shared) select_statement_type ( - conn_, - select_text_, - versioned_, // Process if versioned. - false, // Don't optimize. - id_binding_, - select_image_binding_, - false)); - - return *select_; - } - - delete_statement_type& - delete_statement () - { - if (delete_ == 0) - delete_.reset ( - new (details::shared) delete_statement_type ( - conn_, delete_text_, id_binding_, false)); - - return *delete_; - } - - private: - container_statements (const container_statements&); - container_statements& operator= (const container_statements&); - - protected: - connection_type& conn_; - binding& id_binding_; - - functions_type functions_; - - data_image_type data_image_; - std::size_t data_image_version_; - std::size_t data_id_binding_version_; - - binding insert_image_binding_; - binding select_image_binding_; - - const char* insert_text_; - const char* select_text_; - const char* delete_text_; - - bool versioned_; - const schema_version_migration* svm_; - - details::shared_ptr insert_; - details::shared_ptr select_; - details::shared_ptr delete_; - }; - - template - class smart_container_statements: public container_statements - { - public: - typedef T traits; - typedef typename traits::cond_image_type cond_image_type; - - typedef mssql::update_statement update_statement_type; - typedef mssql::delete_statement delete_statement_type; - - typedef mssql::connection connection_type; - - smart_container_statements (connection_type&, binding& id_binding); - - // Condition image. The image is split into the id (that comes as - // a binding) and index/key/value which is in cond_image_type. - // - cond_image_type& - cond_image () - { - return cond_image_; - } - - bind* - cond_bind () - { - return cond_image_binding_.bind; - } - - bool - cond_binding_test_version () const - { - return cond_id_binding_version_ != this->id_binding_.version || - cond_image_version_ != cond_image_.version || - cond_image_binding_.version == 0; - } - - void - cond_binding_update_version () - { - cond_id_binding_version_ = this->id_binding_.version; - cond_image_version_ = cond_image_.version; - cond_image_binding_.version++; - } - - // Update image. The image is split as follows: value comes - // from the data image, id comes as binding, and index/key - // comes from the condition image. - // - bind* - update_bind () - { - return update_image_binding_.bind; - } - - bool - update_binding_test_version () const - { - return update_id_binding_version_ != this->id_binding_.version || - update_cond_image_version_ != cond_image_.version || - update_data_image_version_ != this->data_image_.version || - update_image_binding_.version == 0; - } - - void - update_binding_update_version () - { - update_id_binding_version_ = this->id_binding_.version; - update_cond_image_version_ = cond_image_.version; - update_data_image_version_ = this->data_image_.version; - update_image_binding_.version++; - } - - // - // Statements. - // - - delete_statement_type& - delete_statement () - { - if (this->delete_ == 0) - this->delete_.reset ( - new (details::shared) delete_statement_type ( - this->conn_, - this->delete_text_, - this->cond_image_binding_, - false)); - - return *this->delete_; - } - - update_statement_type& - update_statement () - { - if (update_ == 0) - update_.reset ( - new (details::shared) update_statement_type ( - this->conn_, - update_text_, - this->versioned_, // Process if versioned. - update_image_binding_, - 0, - false)); - - return *update_; - } - - protected: - cond_image_type cond_image_; - std::size_t cond_image_version_; - std::size_t cond_id_binding_version_; - binding cond_image_binding_; - - std::size_t update_id_binding_version_; - std::size_t update_cond_image_version_; - std::size_t update_data_image_version_; - binding update_image_binding_; - - const char* update_text_; - - details::shared_ptr update_; - }; - - // Template argument is the generated concrete container traits type. - // - template - class container_statements_impl: public T::statements_type - { - public: - typedef T traits; - typedef typename T::statements_type base; - typedef mssql::connection connection_type; - - container_statements_impl (connection_type&, binding&); - - private: - container_statements_impl (const container_statements_impl&); - container_statements_impl& operator= (const container_statements_impl&); - - private: - bind data_image_bind_[traits::data_column_count]; - }; - - template - class smart_container_statements_impl: public container_statements_impl - { - public: - typedef T traits; - typedef mssql::connection connection_type; - - smart_container_statements_impl (connection_type&, binding&); - - private: - bind cond_image_bind_[traits::cond_column_count]; - bind update_image_bind_[traits::value_column_count + - traits::cond_column_count]; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_CONTAINER_STATEMENTS_HXX diff --git a/odb/mssql/container-statements.txx b/odb/mssql/container-statements.txx deleted file mode 100644 index 6a45086..0000000 --- a/odb/mssql/container-statements.txx +++ /dev/null @@ -1,96 +0,0 @@ -// file : odb/mssql/container-statements.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include // std::size_t -#include // std::memset - -namespace odb -{ - namespace mssql - { - // container_statements - // - template - container_statements:: - container_statements (connection_type& conn, binding& id) - : conn_ (conn), - id_binding_ (id), - functions_ (this), - insert_image_binding_ (0, 0), // Initialized by impl. - select_image_binding_ (0, 0), // Initialized by impl. - svm_ (0) - { - functions_.insert_ = &traits::insert; - functions_.select_ = &traits::select; - functions_.delete__ = &traits::delete_; - - data_image_.version = 0; - data_image_version_ = 0; - data_id_binding_version_ = 0; - } - - // smart_container_statements - // - template - smart_container_statements:: - smart_container_statements (connection_type& conn, binding& id) - : container_statements (conn, id), - cond_image_binding_ (0, 0), // Initialized by impl. - update_image_binding_ (0, 0) // Initialized by impl. - { - this->functions_.update_ = &traits::update; - - cond_image_.version = 0; - cond_image_version_ = 0; - cond_id_binding_version_ = 0; - - update_id_binding_version_ = 0; - update_cond_image_version_ = 0; - update_data_image_version_ = 0; - } - - // container_statements_impl - // - template - container_statements_impl:: - container_statements_impl (connection_type& conn, binding& id) - : base (conn, id) - { - this->insert_image_binding_.bind = data_image_bind_; - this->insert_image_binding_.count = traits::data_column_count; - - this->select_image_binding_.bind = data_image_bind_ + - traits::id_column_count; - this->select_image_binding_.count = traits::data_column_count - - traits::id_column_count; - - std::memset (data_image_bind_, 0, sizeof (data_image_bind_)); - - this->insert_text_ = traits::insert_statement; - this->select_text_ = traits::select_statement; - this->delete_text_ = traits::delete_statement; - - this->versioned_ = traits::versioned; - } - - // smart_container_statements_impl - // - template - smart_container_statements_impl:: - smart_container_statements_impl (connection_type& conn, binding& id) - : container_statements_impl (conn, id) - { - this->cond_image_binding_.bind = cond_image_bind_; - this->cond_image_binding_.count = traits::cond_column_count; - - this->update_image_binding_.bind = update_image_bind_; - this->update_image_binding_.count = traits::value_column_count + - traits::cond_column_count; - - std::memset (cond_image_bind_, 0, sizeof (cond_image_bind_)); - std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); - - this->update_text_ = traits::update_statement; - } - } -} diff --git a/odb/mssql/database.cxx b/odb/mssql/database.cxx deleted file mode 100644 index 6e68bcb..0000000 --- a/odb/mssql/database.cxx +++ /dev/null @@ -1,580 +0,0 @@ -// file : odb/mssql/database.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include // std::strcmp, std::strncmp -#include - -#include -#include -#include -#include -#include -#include - -#include - -using namespace std; - -namespace odb -{ - namespace mssql - { - using odb::details::transfer_ptr; - - database:: - database (const string& user, - const string& password, - const string& db, - const string& server, - const string& driver, - const string& extra_connect_string, - transaction_isolation_type transaction_isolation, - SQLHENV environment, - transfer_ptr factory) - : odb::database (id_mssql), - user_ (user), - password_ (password), - db_ (db), - protocol_ (protocol_auto), - port_ (0), - server_ (server), - driver_ (driver), - extra_connect_string_ (extra_connect_string), - transaction_isolation_ (transaction_isolation), - environment_ (environment), - factory_ (factory.transfer ()) - { - init (); - } - - database:: - database (const string& user, - const string& password, - const string& db, - protocol_type protocol, - const string& host, - const string& instance, - const string& driver, - const string& extra_connect_string, - transaction_isolation_type transaction_isolation, - SQLHENV environment, - transfer_ptr factory) - : odb::database (id_mssql), - user_ (user), - password_ (password), - db_ (db), - protocol_ (protocol), - host_ (host), - instance_ (instance), - port_ (0), - driver_ (driver), - extra_connect_string_ (extra_connect_string), - transaction_isolation_ (transaction_isolation), - environment_ (environment), - factory_ (factory.transfer ()) - { - init (); - } - - database:: - database (const string& user, - const string& password, - const string& db, - const string& host, - unsigned int port, - const string& driver, - const string& extra_connect_string, - transaction_isolation_type transaction_isolation, - SQLHENV environment, - transfer_ptr factory) - : odb::database (id_mssql), - user_ (user), - password_ (password), - db_ (db), - protocol_ (protocol_tcp), - host_ (host), - port_ (port), - driver_ (driver), - extra_connect_string_ (extra_connect_string), - transaction_isolation_ (transaction_isolation), - environment_ (environment), - factory_ (factory.transfer ()) - { - init (); - } - - database:: - database (const string& connect_string, - transaction_isolation_type transaction_isolation, - SQLHENV environment, - transfer_ptr factory) - : odb::database (id_mssql), - protocol_ (protocol_auto), - port_ (0), - transaction_isolation_ (transaction_isolation), - connect_string_ (connect_string), - environment_ (environment), - factory_ (factory.transfer ()) - { - init (); - } - - database:: - database (int& argc, - char* argv[], - bool erase, - const string& extra_connect_string, - transaction_isolation_type transaction_isolation, - SQLHENV environment, - transfer_ptr factory) - : odb::database (id_mssql), - protocol_ (protocol_auto), - port_ (0), - extra_connect_string_ (extra_connect_string), - transaction_isolation_ (transaction_isolation), - environment_ (environment), - factory_ (factory.transfer ()) - { - using namespace details; - - try - { - cli::argv_file_scanner scan (argc, argv, "--options-file", erase); - options ops (scan, cli::unknown_mode::skip, cli::unknown_mode::skip); - - user_ = ops.user (); - password_ = ops.password (); - db_ = ops.database (); - server_ = ops.server (); - driver_ = ops.driver (); - } - catch (const cli::exception& e) - { - ostringstream oss; - oss << e; - throw cli_exception (oss.str ()); - } - - init (); - } - - /* - - NOTE: This code hasn't been tested. - - void database:: - parse () - { - // Parse the server string and extract individual parts (protocol, - // host, instance, and port). - // - string port; - - if (server_.compare (0, 4, "lpc:") == 0) - { - // lpc:[\] - // - protocol_ = protocol_shm; - string::size_type p (server_.find (4, '\\')); - - if (p == string::npos) - host_.assign (server_, 4, string::npos); - else - { - host_.assign (server_, 4, p - 4); - instance_.assign (server_, p + 1, string::npos); - } - } - else if (server_.compare (0, 3, "np:") == 0) - { - // np:\pipe\[MSSQL$\]sql\query - // - protocol_ = protocol_pipe; - - string::size_type p (server_.find (3, '\\')); - - if (p != string::npos) - { - host_.assign (server_, 3, p - 3); - - p = server_.find (p + 1, '$'); - - if (p != string::npos) - { - p++; - instance_.assign (server_, p, server_.find (p, '\\') - p); - } - } - } - else - { - // [\][,] - // tcp:[\][,] - // - string::size_type p1 (0), p2; - - if (server_.compare (0, 4, "tcp:") == 0) - { - protocol_ = protocol_tcp; - p1 = 4; - } - - p2 = server_.find (p1, '\\'); - - if (p2 == string::npos) - { - p2 = server_.find (p1, ','); - - if (p2 == string::npos) - host_.assign (server_, p1, string::npos); - else - { - host_.assign (server_, 4, p2 - p1); - port.assign (server_, p2 + 1, string::npos); - } - } - else - { - host_.assign (server_, 4, p2 - p1); - - p1 = server_.find (p2 + 1, ','); - - if (p1 == string::npos) - instance_.assign (server_, p2 + 1, string::npos); - else - { - instance_.assign (server_, p2 + 1, p1 - p2 - 1); - port.assign (server_, p1 + 1, string::npos); - } - } - } - - if (!port.empty ()) - { - istringstream is (port); - is >> port; - protocol_ = protocol_tcp; - } - } - */ - - void database:: - init () - { - SQLRETURN r; - - if (environment_ == 0) - { - r = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &environment_); - - if (!SQL_SUCCEEDED (r)) - throw database_exception ( - 0, "?????", "unable to allocate environment handle"); - - auto_environment_.reset (environment_); - - // Set ODBC version. - // - r = SQLSetEnvAttr (environment_, - SQL_ATTR_ODBC_VERSION, - (SQLPOINTER) SQL_OV_ODBC3, - 0); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, environment_, SQL_HANDLE_ENV); - } - - // Build the connection string. - // - if (connect_string_.empty ()) - { - // Find the driver. - // - if (driver_.empty ()) - { - for (bool first (true);; ) - { - char desc[256]; - SQLSMALLINT desc_size, attr_size; - - r = SQLDriversA (environment_, - first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT, - (SQLCHAR*) desc, - sizeof (desc), - &desc_size, - 0, - 0, - &attr_size); - - if (r == SQL_NO_DATA) - break; - else if (!SQL_SUCCEEDED (r)) - translate_error (r, environment_, SQL_HANDLE_ENV); - - // Native Client 9.0 (first version). - // - if (strcmp (desc, "SQL Native Client") == 0 || - strncmp (desc, "SQL Server Native Client", 24) == 0) - { - // Compare driver strings lexicographically. Provided that - // Microsoft keeps its naming consistent, we will get the - // correct result. For example, "SQL Server Native Client - // 10.0" (SQL Server 2008) will be greater than "SQL Native - // Client" (SQL Server 2005). Similarly, "SQL Server Native - // Client 11.0" (SQL Server 2012) will be preferred over - // "SQL Server Native Client 10.0" (SQL Server 2008). - // - if (desc > driver_) - driver_ = desc; - } - - if (first) - first = false; - } - } - - connect_string_ += "DRIVER={"; - connect_string_ += driver_; - connect_string_ += "};"; - - // If necessary, assemble the server address string, depending - // on which protocol we are using. - if (server_.empty ()) - { - switch (protocol_) - { - case protocol_auto: - { - server_ = (host_.empty () ? "localhost" : host_.c_str ()); - - if (!instance_.empty ()) - { - server_ += '\\'; - server_ += instance_; - } - - break; - } - case protocol_tcp: - { - server_ = "tcp:"; - server_ += (host_.empty () ? "localhost" : host_.c_str ()); - - // Port seems to take precedence over instance. For example, - // if you specify both, and the instance name is invalid, the - // Native Client driver still connects without any problems. - // - if (port_ != 0) - { - ostringstream os; - os << port_; - server_ += ','; - server_ += os.str (); - } - else if (!instance_.empty ()) - { - server_ += '\\'; - server_ += instance_; - } - - break; - } - case protocol_lpc: - { - server_ = "lpc:"; - server_ += (host_.empty () ? "localhost" : host_.c_str ()); - - if (!instance_.empty ()) - { - server_ += '\\'; - server_ += instance_; - } - - break; - } - case protocol_np: - { - server_ = "np:\\\\"; - server_ += (host_.empty () ? "." : host_.c_str ()); - server_ += "\\pipe\\"; - - if (!instance_.empty ()) - { - server_ += "MSSQL$"; - server_ += instance_; - server_ += '\\'; - } - - server_ += "sql\\query"; - break; - } - } - } - - // The Address attribute seems to be preferred over SERVER. However, - // SQL Server 2005 Native Client only seem to support Address since - // SP1. Since we don't know the exact driver version, for now always - // use SERVER with SQL Server 2005 driver. - // - connect_string_ += (driver_ == "SQL Native Client" - ? "SERVER={" - : "Address={"); - - connect_string_ += server_; - connect_string_ += "};"; - - // Add login information. - // - if (user_.empty ()) - // Windows authentication. - // - connect_string_ += "Trusted_Connection=yes;"; - else - { - connect_string_ += "UID={"; - connect_string_ += user_; - connect_string_ += "};"; - - if (!password_.empty ()) - { - connect_string_ += "PWD={"; - connect_string_ += password_; - connect_string_ += "};"; - } - } - - // Add database. - // - if (!db_.empty ()) - { - connect_string_ += "Database={"; - connect_string_ += db_; - connect_string_ += "};"; - } - - // Add any extra connection attributes. - // - if (!extra_connect_string_.empty ()) - connect_string_ += extra_connect_string_; - } - - if (!factory_) - factory_.reset (new connection_pool_factory ()); - - factory_->database (*this); - } - - void database:: - print_usage (ostream& os) - { - details::options::print_usage (os); - } - - database:: - ~database () - { - } - - transaction_impl* database:: - begin () - { - return new transaction_impl (*this); - } - - odb::connection* database:: - connection_ () - { - connection_ptr c (factory_->connect ()); - return c.release (); - } - - const database::schema_version_info& database:: - load_schema_version (const string& name) const - { - schema_version_info& svi (schema_version_map_[name]); - - // Construct the SELECT statement text. - // - string text ("SELECT [version], [migration] FROM "); - - if (!svi.version_table.empty ()) - text += svi.version_table; // Already quoted. - else if (!schema_version_table_.empty ()) - text += schema_version_table_; // Already quoted. - else - text += "[schema_version]"; - - text += " WHERE [name] = ?"; - - // Bind parameters and results. - // - SQLLEN psize[1] = {static_cast (name.size ())}; - bind pbind[1] = { - {bind::string, const_cast (name.c_str ()), &psize[0], 0}}; - binding param (pbind, 1); - param.version++; - - signed char migration; - SQLLEN rsize[2]; - bind rbind[2] = {{bind::bigint, &svi.version, &rsize[0], 0}, - {bind::bit, &migration, &rsize[1], 0}}; - binding result (rbind, 2); - result.version++; - - // If we are not in transaction, start one. - // - transaction t; - if (!transaction::has_current ()) - t.reset (factory_->connect ()->begin (), false); - - mssql::connection& c ( - t.finalized () - ? transaction::current ().connection (const_cast (*this)) - : t.connection (const_cast (*this))); - - try - { - select_statement st (c, - text.c_str (), - false, // Don't process. - false, // Don't optimize. - param, - result, - false); - - st.execute (); - auto_result ar (st); - - switch (st.fetch ()) - { - case select_statement::success: - { - svi.migration = migration != 0; - assert (st.fetch () == select_statement::no_data); - break; - } - case select_statement::no_data: - { - svi.version = 0; // No schema. - break; - } - } - } - catch (const database_exception& e) - { - // Detect the case where there is no version table. The SQL Server- - // specific error code (208) seems to be too generic. - // - if (e.begin ()->sqlstate () == "42S02") - svi.version = 0; // No schema. - else - throw; - } - - if (!t.finalized ()) - t.commit (); - - return svi; - } - } -} diff --git a/odb/mssql/database.hxx b/odb/mssql/database.hxx deleted file mode 100644 index 5367bc5..0000000 --- a/odb/mssql/database.hxx +++ /dev/null @@ -1,629 +0,0 @@ -// file : odb/mssql/database.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_DATABASE_HXX -#define ODB_MSSQL_DATABASE_HXX - -#include - -#include -#include // std::ostream - -#include -#include // ODB_CXX11 -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - class transaction_impl; - - enum protocol - { - protocol_auto, - protocol_tcp, // TCP/IP. - protocol_lpc, // Shared memory (local procedure call). - protocol_np // Named pipes. - }; - - enum transaction_isolation - { - isolation_read_uncommitted, - isolation_read_committed, // SQL Server default. - isolation_repeatable_read, - isolation_snapshot, - isolation_serializable - }; - - class LIBODB_MSSQL_EXPORT database: public odb::database - { - public: - typedef mssql::protocol protocol_type; - typedef mssql::transaction_isolation transaction_isolation_type; - - // Connect to the specified server using the latest available SQL - // Server Native Client ODBC driver by default. If user is empty, - // then use Windows authentication. If db is empty, then use the - // default database for this user. - // - database (const std::string& user, - const std::string& password, - const std::string& db, - const std::string& server, - const std::string& driver = "", - const std::string& extra_connect_string = "", - transaction_isolation_type = isolation_read_committed, - SQLHENV environment = 0, - details::transfer_ptr = - details::transfer_ptr ()); - - // By default connect to the default instance on localhost using - // default protocol and the latest available SQL Server Native - // Client ODBC driver. If user is empty, then use Windows - // authentication. If db is empty, then use the default database - // for this user. - // - database (const std::string& user, - const std::string& password, - const std::string& db, - protocol_type protocol = protocol_auto, - const std::string& host = "", - const std::string& instance = "", - const std::string& driver = "", - const std::string& extra_connect_string = "", - transaction_isolation_type = isolation_read_committed, - SQLHENV environment = 0, - details::transfer_ptr = - details::transfer_ptr ()); - - // Connect using TCP/IP to the specified host and port. If port is - // 0, use the default port (1433). - // - database (const std::string& user, - const std::string& password, - const std::string& db, - const std::string& host, - unsigned int port, - const std::string& driver = "", - const std::string& extra_connect_string = "", - transaction_isolation_type = isolation_read_committed, - SQLHENV environment = 0, - details::transfer_ptr = - details::transfer_ptr ()); - - // Connect using a custom SQL Server Native Client ODBC driver - // conection string. - // - database (const std::string& connect_string, - transaction_isolation_type = isolation_read_committed, - SQLHENV environment = 0, - details::transfer_ptr = - details::transfer_ptr ()); - - // Extract the database parameters from the command line. The - // following options are recognized: - // - // --user | -U - // --password | -P - // --database | -d - // --server | -S - // --driver - // --options-file - // - // For more information, see the output of the print_usage() function - // below. If erase is true, the above options are removed from the - // argv array and the argc count is updated accordingly. This - // constructor may throw the cli_exception exception. - // - database (int& argc, - char* argv[], - bool erase = false, - const std::string& extra_connect_string = "", - transaction_isolation_type = isolation_read_committed, - SQLHENV environment = 0, - details::transfer_ptr = - details::transfer_ptr ()); - - // Move-constructible but not move-assignable. - // - // Note: noexcept is not specified since odb::database(odb::database&&) - // can throw. - // -#ifdef ODB_CXX11 - database (database&&); -#endif - - static void - print_usage (std::ostream&); - - // Object persistence API. - // - public: - - // Make the object persistent. - // - template - typename object_traits::id_type - persist (T& object); - - template - typename object_traits::id_type - persist (const T& object); - - template - typename object_traits::id_type - persist (T* obj_ptr); - - template class P> - typename object_traits::id_type - persist (const P& obj_ptr); - - template class P> - typename object_traits::id_type - persist (const P& obj_ptr); - - template class P> - typename object_traits::id_type - persist (P& obj_ptr); - - template class P> - typename object_traits::id_type - persist (P& obj_ptr); - - template - typename object_traits::id_type - persist (const typename object_traits::pointer_type& obj_ptr); - - // Bulk persist. Can be a range of references or pointers (including - // smart pointers) to objects. - // - template - void - persist (I begin, I end, bool continue_failed = true); - - // Load an object. Throw object_not_persistent if not found. - // - template - typename object_traits::pointer_type - load (const typename object_traits::id_type& id); - - template - void - load (const typename object_traits::id_type& id, T& object); - - // Load (or reload, if it is already loaded) a section of an object. - // - template - void - load (T& object, section&); - - // Reload an object. - // - template - void - reload (T& object); - - template - void - reload (T* obj_ptr); - - template class P> - void - reload (const P& obj_ptr); - - template class P> - void - reload (const P& obj_ptr); - - template class P> - void - reload (P& obj_ptr); - - template class P> - void - reload (P& obj_ptr); - - template - void - reload (const typename object_traits::pointer_type& obj_ptr); - - // Loan an object if found. Return NULL/false if not found. - // - template - typename object_traits::pointer_type - find (const typename object_traits::id_type& id); - - template - bool - find (const typename object_traits::id_type& id, T& object); - - // Update the state of a modified objects. - // - template - void - update (T& object); - - template - void - update (T* obj_ptr); - - template class P> - void - update (const P& obj_ptr); - - template class P> - void - update (const P& obj_ptr); - - template class P> - void - update (P& obj_ptr); - - template class P> - void - update (P& obj_ptr); - - template - void - update (const typename object_traits::pointer_type& obj_ptr); - - // Bulk update. Can be a range of references or pointers (including - // smart pointers) to objects. - // - template - void - update (I begin, I end, bool continue_failed = true); - - // Update a section of an object. Throws the section_not_loaded - // exception if the section is not loaded. Note also that this - // function does not clear the changed flag if it is set. - // - template - void - update (const T& object, const section&); - - // Make the object transient. Throw object_not_persistent if not - // found. - // - template - void - erase (const typename object_traits::id_type& id); - - template - void - erase (T& object); - - template - void - erase (T* obj_ptr); - - template class P> - void - erase (const P& obj_ptr); - - template class P> - void - erase (const P& obj_ptr); - - template class P> - void - erase (P& obj_ptr); - - template class P> - void - erase (P& obj_ptr); - - template - void - erase (const typename object_traits::pointer_type& obj_ptr); - - // Bulk erase. - // - template - void - erase (I id_begin, I id_end, bool continue_failed = true); - - // Can be a range of references or pointers (including smart pointers) - // to objects. - // - template - void - erase (I obj_begin, I obj_end, bool continue_failed = true); - - // Erase multiple objects matching a query predicate. - // - template - unsigned long long - erase_query (); - - template - unsigned long long - erase_query (const char*); - - template - unsigned long long - erase_query (const std::string&); - - template - unsigned long long - erase_query (const mssql::query_base&); - - template - unsigned long long - erase_query (const odb::query_base&); - - // Query API. - // - template - result - query (); - - template - result - query (const char*); - - template - result - query (const std::string&); - - template - result - query (const mssql::query_base&); - - template - result - query (const odb::query_base&); - - // Query one API. - // - template - typename result::pointer_type - query_one (); - - template - bool - query_one (T& object); - - template - T - query_value (); - - template - typename result::pointer_type - query_one (const char*); - - template - bool - query_one (const char*, T& object); - - template - T - query_value (const char*); - - template - typename result::pointer_type - query_one (const std::string&); - - template - bool - query_one (const std::string&, T& object); - - template - T - query_value (const std::string&); - - template - typename result::pointer_type - query_one (const mssql::query_base&); - - template - bool - query_one (const mssql::query_base&, T& object); - - template - T - query_value (const mssql::query_base&); - - template - typename result::pointer_type - query_one (const odb::query_base&); - - template - bool - query_one (const odb::query_base&, T& object); - - template - T - query_value (const odb::query_base&); - - // Query preparation. - // - template - prepared_query - prepare_query (const char* name, const char*); - - template - prepared_query - prepare_query (const char* name, const std::string&); - - template - prepared_query - prepare_query (const char* name, const mssql::query_base&); - - template - prepared_query - prepare_query (const char* name, const odb::query_base&); - - // Transactions. - // - public: - virtual transaction_impl* - begin (); - - public: - connection_ptr - connection (); - - public: - const std::string& - user () const - { - return user_; - } - - const std::string& - password () const - { - return password_; - } - - const std::string& - db () const - { - return db_; - } - - protocol_type - protocol () const - { - return protocol_; - } - - const std::string& - host () const - { - return host_; - } - - const std::string& - instance () const - { - return instance_; - } - - unsigned int - port () const - { - return port_; - } - - const std::string& - server () const - { - return server_; - } - - const std::string& - driver () const - { - return driver_; - } - - const std::string& - extra_connect_string () const - { - return extra_connect_string_; - } - - transaction_isolation_type - transaction_isolation () const - { - return transaction_isolation_; - } - - const std::string& - connect_string () const - { - return connect_string_; - } - - SQLHENV - environment () - { - return environment_; - } - - // SQL statement tracing. - // - public: - typedef mssql::tracer tracer_type; - - void - tracer (tracer_type& t) - { - odb::database::tracer (t); - } - - void - tracer (tracer_type* t) - { - odb::database::tracer (t); - } - - using odb::database::tracer; - - // Database schema version. - // - protected: - virtual const schema_version_info& - load_schema_version (const std::string& schema_name) const; - - public: - // Database id constant (useful for meta-programming). - // - static const odb::database_id database_id = id_mssql; - - public: - virtual - ~database (); - - protected: - virtual odb::connection* - connection_ (); - - private: - void - init (); - - private: - // Note: remember to update move ctor if adding any new members. - // - std::string user_; - std::string password_; - std::string db_; - protocol_type protocol_; - std::string host_; - std::string instance_; - unsigned int port_; - std::string server_; - std::string driver_; - std::string extra_connect_string_; - transaction_isolation_type transaction_isolation_; - std::string connect_string_; - - auto_handle auto_environment_; - SQLHENV environment_; - - details::unique_ptr factory_; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_DATABASE_HXX diff --git a/odb/mssql/database.ixx b/odb/mssql/database.ixx deleted file mode 100644 index ae1b83b..0000000 --- a/odb/mssql/database.ixx +++ /dev/null @@ -1,644 +0,0 @@ -// file : odb/mssql/database.ixx -// license : ODB NCUEL; see accompanying LICENSE file - -#include // move() - -#include - -namespace odb -{ - namespace mssql - { -#ifdef ODB_CXX11 - inline database:: - database (database&& db) // Has to be inline. - : odb::database (std::move (db)), - user_ (std::move (db.user_)), - password_ (std::move (db.password_)), - db_ (std::move (db.db_)), - protocol_ (db.protocol_), - host_ (std::move (db.host_)), - instance_ (std::move (db.instance_)), - port_ (db.port_), - server_ (std::move (db.server_)), - driver_ (std::move (db.driver_)), - extra_connect_string_ (std::move (db.extra_connect_string_)), - transaction_isolation_ (db.transaction_isolation_), - connect_string_ (std::move (db.connect_string_)), - auto_environment_ (std::move (db.auto_environment_)), - environment_ (db.environment_), - factory_ (std::move (db.factory_)) - { - factory_->database (*this); // New database instance. - } -#endif - - inline connection_ptr database:: - connection () - { - // Go through the virtual connection_() function instead of - // directly to allow overriding. - // - return connection_ptr ( - static_cast (connection_ ())); - } - - template - inline typename object_traits::id_type database:: - persist (T& obj) - { - return persist_ (obj); - } - - template - inline typename object_traits::id_type database:: - persist (const T& obj) - { - return persist_ (obj); - } - - template - inline typename object_traits::id_type database:: - persist (T* p) - { - typedef typename object_traits::pointer_type object_pointer; - - // The passed pointer should be the same or implicit-convertible - // to the object pointer. This way we make sure the object pointer - // does not assume ownership of the passed object. - // - const object_pointer& pobj (p); - - return persist_ (pobj); - } - - template class P> - inline typename object_traits::id_type database:: - persist (const P& p) - { - typedef typename object_traits::pointer_type object_pointer; - - // The passed pointer should be the same or implicit-convertible - // to the object pointer. This way we make sure the object pointer - // does not assume ownership of the passed object. - // - const object_pointer& pobj (p); - - return persist_ (pobj); - } - - template class P> - inline typename object_traits::id_type database:: - persist (const P& p) - { - typedef typename object_traits::pointer_type object_pointer; - - // The passed pointer should be the same or implicit-convertible - // to the object pointer. This way we make sure the object pointer - // does not assume ownership of the passed object. - // - const object_pointer& pobj (p); - - return persist_ (pobj); - } - - template class P> - inline typename object_traits::id_type database:: - persist (P& p) - { - const P& cr (p); - return persist (cr); - } - - template class P> - inline typename object_traits::id_type database:: - persist (P& p) - { - const P& cr (p); - return persist (cr); - } - - template - inline typename object_traits::id_type database:: - persist (const typename object_traits::pointer_type& pobj) - { - return persist_ (pobj); - } - - template - inline void database:: - persist (I b, I e, bool cont) - { - persist_ (b, e, cont); - } - - template - inline typename object_traits::pointer_type database:: - load (const typename object_traits::id_type& id) - { - return load_ (id); - } - - template - inline void database:: - load (const typename object_traits::id_type& id, T& obj) - { - return load_ (id, obj); - } - - template - inline void database:: - load (T& obj, section& s) - { - return load_ (obj, s); - } - - template - inline typename object_traits::pointer_type database:: - find (const typename object_traits::id_type& id) - { - return find_ (id); - } - - template - inline bool database:: - find (const typename object_traits::id_type& id, T& obj) - { - return find_ (id, obj); - } - - template - inline void database:: - reload (T& obj) - { - reload_ (obj); - } - - template - inline void database:: - reload (T* p) - { - reload (*p); - } - - template class P> - inline void database:: - reload (const P& p) - { - reload (odb::pointer_traits< P >::get_ref (p)); - } - - template class P> - inline void database:: - reload (const P& p) - { - reload (odb::pointer_traits< P >::get_ref (p)); - } - - template class P> - inline void database:: - reload (P& p) - { - reload (odb::pointer_traits< P >::get_ref (p)); - } - - template class P> - inline void database:: - reload (P& p) - { - reload (odb::pointer_traits< P >::get_ref (p)); - } - - template - inline void database:: - reload (const typename object_traits::pointer_type& pobj) - { - typedef typename object_traits::pointer_type pointer_type; - - reload (odb::pointer_traits::get_ref (pobj)); - } - - template - inline void database:: - update (T& obj) - { - update_ (obj); - } - - template - inline void database:: - update (T* p) - { - typedef typename object_traits::pointer_type object_pointer; - - // The passed pointer should be the same or implicit-convertible - // to the object pointer. This way we make sure the object pointer - // does not assume ownership of the passed object. - // - const object_pointer& pobj (p); - - update_ (pobj); - } - - template class P> - inline void database:: - update (const P& p) - { - typedef typename object_traits::pointer_type object_pointer; - - // The passed pointer should be the same or implicit-convertible - // to the object pointer. This way we make sure the object pointer - // does not assume ownership of the passed object. - // - const object_pointer& pobj (p); - - update_ (pobj); - } - - template class P> - inline void database:: - update (const P& p) - { - typedef typename object_traits::pointer_type object_pointer; - - // The passed pointer should be the same or implicit-convertible - // to the object pointer. This way we make sure the object pointer - // does not assume ownership of the passed object. - // - const object_pointer& pobj (p); - - update_ (pobj); - } - - template class P> - inline void database:: - update (P& p) - { - const P& cr (p); - update (cr); - } - - template class P> - inline void database:: - update (P& p) - { - const P& cr (p); - update (cr); - } - - template - inline void database:: - update (const typename object_traits::pointer_type& pobj) - { - update_ (pobj); - } - - template - inline void database:: - update (I b, I e, bool cont) - { - update_ (b, e, cont); - } - - template - inline void database:: - update (const T& obj, const section& s) - { - update_ (obj, s); - } - - template - inline void database:: - erase (const typename object_traits::id_type& id) - { - return erase_ (id); - } - - template - inline void database:: - erase (T& obj) - { - return erase_ (obj); - } - - template - inline void database:: - erase (T* p) - { - typedef typename object_traits::pointer_type object_pointer; - - // The passed pointer should be the same or implicit-convertible - // to the object pointer. This way we make sure the object pointer - // does not assume ownership of the passed object. - // - const object_pointer& pobj (p); - - erase_ (pobj); - } - - template class P> - inline void database:: - erase (const P& p) - { - typedef typename object_traits::pointer_type object_pointer; - - // The passed pointer should be the same or implicit-convertible - // to the object pointer. This way we make sure the object pointer - // does not assume ownership of the passed object. - // - const object_pointer& pobj (p); - - erase_ (pobj); - } - - template class P> - inline void database:: - erase (const P& p) - { - typedef typename object_traits::pointer_type object_pointer; - - // The passed pointer should be the same or implicit-convertible - // to the object pointer. This way we make sure the object pointer - // does not assume ownership of the passed object. - // - const object_pointer& pobj (p); - - erase_ (pobj); - } - - template class P> - inline void database:: - erase (P& p) - { - const P& cr (p); - erase (cr); - } - - template class P> - inline void database:: - erase (P& p) - { - const P& cr (p); - erase (cr); - } - - template - inline void database:: - erase (const typename object_traits::pointer_type& pobj) - { - erase_ (pobj); - } - - template - inline void database:: - erase (I idb, I ide, bool cont) - { - erase_id_ (idb, ide, cont); - } - - template - inline void database:: - erase (I ob, I oe, bool cont) - { - erase_object_ (ob, oe, cont); - } - - template - inline unsigned long long database:: - erase_query () - { - // T is always object_type. - // - return erase_query (mssql::query_base ()); - } - - template - inline unsigned long long database:: - erase_query (const char* q) - { - // T is always object_type. - // - return erase_query (mssql::query_base (q)); - } - - template - inline unsigned long long database:: - erase_query (const std::string& q) - { - // T is always object_type. - // - return erase_query (mssql::query_base (q)); - } - - template - inline unsigned long long database:: - erase_query (const mssql::query_base& q) - { - // T is always object_type. - // - return object_traits_impl::erase_query (*this, q); - } - - template - inline unsigned long long database:: - erase_query (const odb::query_base& q) - { - // Translate to native query. - // - return erase_query (mssql::query_base (q)); - } - - template - inline result database:: - query () - { - return query (mssql::query_base ()); - } - - template - inline result database:: - query (const char* q) - { - return query (mssql::query_base (q)); - } - - template - inline result database:: - query (const std::string& q) - { - return query (mssql::query_base (q)); - } - - template - inline result database:: - query (const mssql::query_base& q) - { - // T is always object_type. We also don't need to check for transaction - // here; object_traits::query () does this. - // - return query_::call (*this, q); - } - - template - inline result database:: - query (const odb::query_base& q) - { - // Translate to native query. - // - return query (mssql::query_base (q)); - } - - template - inline typename result::pointer_type database:: - query_one () - { - return query_one (mssql::query_base ()); - } - - template - inline bool database:: - query_one (T& o) - { - return query_one (mssql::query_base (), o); - } - - template - inline T database:: - query_value () - { - return query_value (mssql::query_base ()); - } - - template - inline typename result::pointer_type database:: - query_one (const char* q) - { - return query_one (mssql::query_base (q)); - } - - template - inline bool database:: - query_one (const char* q, T& o) - { - return query_one (mssql::query_base (q), o); - } - - template - inline T database:: - query_value (const char* q) - { - return query_value (mssql::query_base (q)); - } - - template - inline typename result::pointer_type database:: - query_one (const std::string& q) - { - return query_one (mssql::query_base (q)); - } - - template - inline bool database:: - query_one (const std::string& q, T& o) - { - return query_one (mssql::query_base (q), o); - } - - template - inline T database:: - query_value (const std::string& q) - { - return query_value (mssql::query_base (q)); - } - - template - inline typename result::pointer_type database:: - query_one (const mssql::query_base& q) - { - // T is always object_type. We also don't need to check for transaction - // here; object_traits::query () does this. - // - return query_one_ (q); - } - - template - inline bool database:: - query_one (const mssql::query_base& q, T& o) - { - // T is always object_type. We also don't need to check for transaction - // here; object_traits::query () does this. - // - return query_one_ (q, o); - } - - template - inline T database:: - query_value (const mssql::query_base& q) - { - // T is always object_type. We also don't need to check for transaction - // here; object_traits::query () does this. - // - return query_value_ (q); - } - - template - inline typename result::pointer_type database:: - query_one (const odb::query_base& q) - { - // Translate to native query. - // - return query_one (mssql::query_base (q)); - } - - template - inline bool database:: - query_one (const odb::query_base& q, T& o) - { - // Translate to native query. - // - return query_one (mssql::query_base (q), o); - } - - template - inline T database:: - query_value (const odb::query_base& q) - { - // Translate to native query. - // - return query_value (mssql::query_base (q)); - } - - template - inline prepared_query database:: - prepare_query (const char* n, const char* q) - { - return prepare_query (n, mssql::query_base (q)); - } - - template - inline prepared_query database:: - prepare_query (const char* n, const std::string& q) - { - return prepare_query (n, mssql::query_base (q)); - } - - template - inline prepared_query database:: - prepare_query (const char* n, const mssql::query_base& q) - { - // Throws if not in transaction. - // - mssql::connection& c (transaction::current ().connection (*this)); - return c.prepare_query (n, q); - } - - template - inline prepared_query database:: - prepare_query (const char* n, const odb::query_base& q) - { - // Translate to native query. - // - return prepare_query (n, mssql::query_base (q)); - } - } -} diff --git a/odb/mssql/details/.gitignore b/odb/mssql/details/.gitignore deleted file mode 100644 index b298f89..0000000 --- a/odb/mssql/details/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/options.?xx diff --git a/odb/mssql/details/build2/config-stub.h b/odb/mssql/details/build2/config-stub.h deleted file mode 100644 index e402d2f..0000000 --- a/odb/mssql/details/build2/config-stub.h +++ /dev/null @@ -1,5 +0,0 @@ -/* file : odb/mssql/details/build2/config-stub.h - * license : ODB NCUEL; see accompanying LICENSE file - */ - -#include diff --git a/odb/mssql/details/build2/config-vc-stub.h b/odb/mssql/details/build2/config-vc-stub.h deleted file mode 100644 index 36ae27f..0000000 --- a/odb/mssql/details/build2/config-vc-stub.h +++ /dev/null @@ -1,5 +0,0 @@ -/* file : odb/mssql/details/build2/config-vc-stub.h - * license : ODB NCUEL; see accompanying LICENSE file - */ - -#include diff --git a/odb/mssql/details/build2/config-vc.h b/odb/mssql/details/build2/config-vc.h deleted file mode 100644 index 1489d09..0000000 --- a/odb/mssql/details/build2/config-vc.h +++ /dev/null @@ -1,15 +0,0 @@ -/* file : odb/mssql/details/build2/config-vc.h - * license : ODB NCUEL; see accompanying LICENSE file - */ - -/* Configuration file for Windows/VC++ for the build2 build. */ - -#ifndef ODB_MSSQL_DETAILS_CONFIG_VC_H -#define ODB_MSSQL_DETAILS_CONFIG_VC_H - -/* Define LIBODB_MSSQL_BUILD2 for the installed case. */ -#ifndef LIBODB_MSSQL_BUILD2 -# define LIBODB_MSSQL_BUILD2 -#endif - -#endif /* ODB_MSSQL_DETAILS_CONFIG_VC_H */ diff --git a/odb/mssql/details/build2/config.h b/odb/mssql/details/build2/config.h deleted file mode 100644 index de736e2..0000000 --- a/odb/mssql/details/build2/config.h +++ /dev/null @@ -1,17 +0,0 @@ -/* file : odb/mssql/details/build2/config.h - * license : ODB NCUEL; see accompanying LICENSE file - */ - -/* Static configuration file for the build2 build. The installed case - (when LIBODB_MSSQL_BUILD2 is not necessarily defined) is the only - reason we have it. */ - -#ifndef ODB_MSSQL_DETAILS_CONFIG_H -#define ODB_MSSQL_DETAILS_CONFIG_H - -/* Define LIBODB_MSSQL_BUILD2 for the installed case. */ -#ifndef LIBODB_MSSQL_BUILD2 -# define LIBODB_MSSQL_BUILD2 -#endif - -#endif /* ODB_MSSQL_DETAILS_CONFIG_H */ diff --git a/odb/mssql/details/config-vc.h b/odb/mssql/details/config-vc.h deleted file mode 100644 index e93b86b..0000000 --- a/odb/mssql/details/config-vc.h +++ /dev/null @@ -1,5 +0,0 @@ -/* file : odb/mssql/details/config-vc.h - * license : ODB NCUEL; see accompanying LICENSE file - */ - -/* Dummy configuration file for Windows/VC++. */ diff --git a/odb/mssql/details/config.h.in b/odb/mssql/details/config.h.in deleted file mode 100644 index 9ddb75a..0000000 --- a/odb/mssql/details/config.h.in +++ /dev/null @@ -1,12 +0,0 @@ -/* file : odb/mssql/details/config.h.in - * license : ODB NCUEL; see accompanying LICENSE file - */ - -/* This file is automatically processed by configure. */ - -#ifndef ODB_MSSQL_DETAILS_CONFIG_H -#define ODB_MSSQL_DETAILS_CONFIG_H - -#undef LIBODB_MSSQL_STATIC_LIB - -#endif /* ODB_MSSQL_DETAILS_CONFIG_H */ diff --git a/odb/mssql/details/config.hxx b/odb/mssql/details/config.hxx deleted file mode 100644 index ff2a5af..0000000 --- a/odb/mssql/details/config.hxx +++ /dev/null @@ -1,21 +0,0 @@ -// file : odb/mssql/details/config.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_DETAILS_CONFIG_HXX -#define ODB_MSSQL_DETAILS_CONFIG_HXX - -// no pre - -#ifdef ODB_COMPILER -# error libodb-mssql header included in odb-compiled header -#elif !defined(LIBODB_MSSQL_BUILD2) -# ifdef _MSC_VER -# include -# else -# include -# endif -#endif - -// no post - -#endif // ODB_MSSQL_DETAILS_CONFIG_HXX diff --git a/odb/mssql/details/conversion.hxx b/odb/mssql/details/conversion.hxx deleted file mode 100644 index 35f368d..0000000 --- a/odb/mssql/details/conversion.hxx +++ /dev/null @@ -1,58 +0,0 @@ -// file : odb/mssql/details/conversion.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_DETAILS_CONVERSION_HXX -#define ODB_MSSQL_DETAILS_CONVERSION_HXX - -#include - -#include - -namespace odb -{ - // @@ Revise this. - // - namespace details {} - - namespace mssql - { - namespace details - { - using namespace odb::details; - - // Detect whether conversion is specified in type_traits. - // - template - meta::yes - conversion_p_test (typename type_traits::conversion*); - - template - meta::no - conversion_p_test (...); - - template - struct conversion_p - { - static const bool value = - sizeof (conversion_p_test (0)) == sizeof (meta::yes); - }; - - template ::value> - struct conversion; - - template - struct conversion - { - static const char* to () {return type_traits::conversion::to ();} - }; - - template - struct conversion - { - static const char* to () {return 0;} - }; - } - } -} - -#endif // ODB_MSSQL_DETAILS_CONVERSION_HXX diff --git a/odb/mssql/details/export.hxx b/odb/mssql/details/export.hxx deleted file mode 100644 index 94e762b..0000000 --- a/odb/mssql/details/export.hxx +++ /dev/null @@ -1,78 +0,0 @@ -// file : odb/mssql/details/export.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_DETAILS_EXPORT_HXX -#define ODB_MSSQL_DETAILS_EXPORT_HXX - -#include - -#include - -// Normally we don't export class templates (but do complete specializations), -// inline functions, and classes with only inline member functions. Exporting -// classes that inherit from non-exported/imported bases (e.g., std::string) -// will end up badly. The only known workarounds are to not inherit or to not -// export. Also, MinGW GCC doesn't like seeing non-exported function being -// used before their inline definition. The workaround is to reorder code. In -// the end it's all trial and error. - -#ifdef LIBODB_MSSQL_BUILD2 - -#if defined(LIBODB_MSSQL_STATIC) // Using static. -# define LIBODB_MSSQL_EXPORT -#elif defined(LIBODB_MSSQL_STATIC_BUILD) // Building static. -# define LIBODB_MSSQL_EXPORT -#elif defined(LIBODB_MSSQL_SHARED) // Using shared. -# ifdef _WIN32 -# define LIBODB_MSSQL_EXPORT __declspec(dllimport) -# else -# define LIBODB_MSSQL_EXPORT -# endif -#elif defined(LIBODB_MSSQL_SHARED_BUILD) // Building shared. -# ifdef _WIN32 -# define LIBODB_MSSQL_EXPORT __declspec(dllexport) -# else -# define LIBODB_MSSQL_EXPORT -# endif -#else -// If none of the above macros are defined, then we assume we are being used -// by some third-party build system that cannot/doesn't signal the library -// type. Note that this fallback works for both static and shared but in case -// of shared will be sub-optimal compared to having dllimport. -// -# define LIBODB_MSSQL_EXPORT // Using static or shared. -#endif - -#else // LIBODB_MSSQL_BUILD2 - -#ifdef LIBODB_MSSQL_STATIC_LIB -# define LIBODB_MSSQL_EXPORT -#else -# ifdef _WIN32 -# ifdef _MSC_VER -# ifdef LIBODB_MSSQL_DYNAMIC_LIB -# define LIBODB_MSSQL_EXPORT __declspec(dllexport) -# else -# define LIBODB_MSSQL_EXPORT __declspec(dllimport) -# endif -# else -# ifdef LIBODB_MSSQL_DYNAMIC_LIB -# ifdef DLL_EXPORT -# define LIBODB_MSSQL_EXPORT __declspec(dllexport) -# else -# define LIBODB_MSSQL_EXPORT -# endif -# else -# define LIBODB_MSSQL_EXPORT __declspec(dllimport) -# endif -# endif -# else -# define LIBODB_MSSQL_EXPORT -# endif -#endif - -#endif // LIBODB_MSSQL_BUILD2 - -#include - -#endif // ODB_MSSQL_DETAILS_EXPORT_HXX diff --git a/odb/mssql/details/options.cli b/odb/mssql/details/options.cli deleted file mode 100644 index dcf92e5..0000000 --- a/odb/mssql/details/options.cli +++ /dev/null @@ -1,63 +0,0 @@ -// file : odb/mssql/details/options.cli -// license : ODB NCUEL; see accompanying LICENSE file - -include ; - -namespace odb -{ - namespace mssql - { - namespace details - { - class options - { - std::string --user | -U - { - "", - "SQL Server database user. If not specified, then Windows - authentication is used." - }; - - std::string --password | -P - { - "", - "SQL Server database password. Omit this option if the user - password is blank or Windows authentication is used." - }; - - std::string --database | -d - { - "", - "SQL Server database name. If not specified, then the default - database for this user is used." - }; - - std::string --server | -S - { - "", - "SQL Server instance address in the - \c{[\i{protocol}\b{:}]\i{host}[\b{\\}\i{instance}][\b{,}\i{port}]} - format, where \ci{protocol} can be \cb{tcp} (TCP/IP), - \cb{lpc} (shared memory), or \cb{np} (named pipe). If not specifid, - then \cb{localhost} is used." - }; - - std::string --driver - { - "", - "SQL Server Native Client ODBC driver name. If not specified, then - the latest available driver is used." - }; - - std::string --options-file - { - "", - "Read additional options from . Each option should appear on a - separate line optionally followed by space or equal sign (\cb{=}) - and an option value. Empty lines and lines starting with \cb{#} are - ignored." - }; - }; - } - } -} diff --git a/odb/mssql/details/pregenerated/odb/mssql/details/options.cxx b/odb/mssql/details/pregenerated/odb/mssql/details/options.cxx deleted file mode 100644 index 905beb8..0000000 --- a/odb/mssql/details/pregenerated/odb/mssql/details/options.cxx +++ /dev/null @@ -1,1125 +0,0 @@ -// -*- C++ -*- -// -// This file was generated by CLI, a command line interface -// compiler for C++. -// - -// Begin prologue. -// -// -// End prologue. - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace odb -{ - namespace mssql - { - namespace details - { - namespace cli - { - // unknown_option - // - unknown_option:: - ~unknown_option () throw () - { - } - - void unknown_option:: - print (::std::ostream& os) const - { - os << "unknown option '" << option ().c_str () << "'"; - } - - const char* unknown_option:: - what () const throw () - { - return "unknown option"; - } - - // unknown_argument - // - unknown_argument:: - ~unknown_argument () throw () - { - } - - void unknown_argument:: - print (::std::ostream& os) const - { - os << "unknown argument '" << argument ().c_str () << "'"; - } - - const char* unknown_argument:: - what () const throw () - { - return "unknown argument"; - } - - // missing_value - // - missing_value:: - ~missing_value () throw () - { - } - - void missing_value:: - print (::std::ostream& os) const - { - os << "missing value for option '" << option ().c_str () << "'"; - } - - const char* missing_value:: - what () const throw () - { - return "missing option value"; - } - - // invalid_value - // - invalid_value:: - ~invalid_value () throw () - { - } - - void invalid_value:: - print (::std::ostream& os) const - { - os << "invalid value '" << value ().c_str () << "' for option '" - << option ().c_str () << "'"; - - if (!message ().empty ()) - os << ": " << message ().c_str (); - } - - const char* invalid_value:: - what () const throw () - { - return "invalid option value"; - } - - // eos_reached - // - void eos_reached:: - print (::std::ostream& os) const - { - os << what (); - } - - const char* eos_reached:: - what () const throw () - { - return "end of argument stream reached"; - } - - // file_io_failure - // - file_io_failure:: - ~file_io_failure () throw () - { - } - - void file_io_failure:: - print (::std::ostream& os) const - { - os << "unable to open file '" << file ().c_str () << "' or read failure"; - } - - const char* file_io_failure:: - what () const throw () - { - return "unable to open file or read failure"; - } - - // unmatched_quote - // - unmatched_quote:: - ~unmatched_quote () throw () - { - } - - void unmatched_quote:: - print (::std::ostream& os) const - { - os << "unmatched quote in argument '" << argument ().c_str () << "'"; - } - - const char* unmatched_quote:: - what () const throw () - { - return "unmatched quote"; - } - - // scanner - // - scanner:: - ~scanner () - { - } - - // argv_scanner - // - bool argv_scanner:: - more () - { - return i_ < argc_; - } - - const char* argv_scanner:: - peek () - { - if (i_ < argc_) - return argv_[i_]; - else - throw eos_reached (); - } - - const char* argv_scanner:: - next () - { - if (i_ < argc_) - { - const char* r (argv_[i_]); - - if (erase_) - { - for (int i (i_ + 1); i < argc_; ++i) - argv_[i - 1] = argv_[i]; - - --argc_; - argv_[argc_] = 0; - } - else - ++i_; - - ++start_position_; - return r; - } - else - throw eos_reached (); - } - - void argv_scanner:: - skip () - { - if (i_ < argc_) - { - ++i_; - ++start_position_; - } - else - throw eos_reached (); - } - - std::size_t argv_scanner:: - position () - { - return start_position_; - } - - // argv_file_scanner - // - int argv_file_scanner::zero_argc_ = 0; - std::string argv_file_scanner::empty_string_; - - bool argv_file_scanner:: - more () - { - if (!args_.empty ()) - return true; - - while (base::more ()) - { - // See if the next argument is the file option. - // - const char* a (base::peek ()); - const option_info* oi = 0; - const char* ov = 0; - - if (!skip_) - { - if ((oi = find (a)) != 0) - { - base::next (); - - if (!base::more ()) - throw missing_value (a); - - ov = base::next (); - } - else if (std::strncmp (a, "-", 1) == 0) - { - if ((ov = std::strchr (a, '=')) != 0) - { - std::string o (a, 0, ov - a); - if ((oi = find (o.c_str ())) != 0) - { - base::next (); - ++ov; - } - } - } - } - - if (oi != 0) - { - if (oi->search_func != 0) - { - std::string f (oi->search_func (ov, oi->arg)); - - if (!f.empty ()) - load (f); - } - else - load (ov); - - if (!args_.empty ()) - return true; - } - else - { - if (!skip_) - skip_ = (std::strcmp (a, "--") == 0); - - return true; - } - } - - return false; - } - - const char* argv_file_scanner:: - peek () - { - if (!more ()) - throw eos_reached (); - - return args_.empty () ? base::peek () : args_.front ().value.c_str (); - } - - const std::string& argv_file_scanner:: - peek_file () - { - if (!more ()) - throw eos_reached (); - - return args_.empty () ? empty_string_ : *args_.front ().file; - } - - std::size_t argv_file_scanner:: - peek_line () - { - if (!more ()) - throw eos_reached (); - - return args_.empty () ? 0 : args_.front ().line; - } - - const char* argv_file_scanner:: - next () - { - if (!more ()) - throw eos_reached (); - - if (args_.empty ()) - return base::next (); - else - { - hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value); - args_.pop_front (); - ++start_position_; - return hold_[i_].c_str (); - } - } - - void argv_file_scanner:: - skip () - { - if (!more ()) - throw eos_reached (); - - if (args_.empty ()) - return base::skip (); - else - { - args_.pop_front (); - ++start_position_; - } - } - - const argv_file_scanner::option_info* argv_file_scanner:: - find (const char* a) const - { - for (std::size_t i (0); i < options_count_; ++i) - if (std::strcmp (a, options_[i].option) == 0) - return &options_[i]; - - return 0; - } - - std::size_t argv_file_scanner:: - position () - { - return start_position_; - } - - void argv_file_scanner:: - load (const std::string& file) - { - using namespace std; - - ifstream is (file.c_str ()); - - if (!is.is_open ()) - throw file_io_failure (file); - - files_.push_back (file); - - arg a; - a.file = &*files_.rbegin (); - - for (a.line = 1; !is.eof (); ++a.line) - { - string line; - getline (is, line); - - if (is.fail () && !is.eof ()) - throw file_io_failure (file); - - string::size_type n (line.size ()); - - // Trim the line from leading and trailing whitespaces. - // - if (n != 0) - { - const char* f (line.c_str ()); - const char* l (f + n); - - const char* of (f); - while (f < l && (*f == ' ' || *f == '\t' || *f == '\r')) - ++f; - - --l; - - const char* ol (l); - while (l > f && (*l == ' ' || *l == '\t' || *l == '\r')) - --l; - - if (f != of || l != ol) - line = f <= l ? string (f, l - f + 1) : string (); - } - - // Ignore empty lines, those that start with #. - // - if (line.empty () || line[0] == '#') - continue; - - string::size_type p (string::npos); - if (line.compare (0, 1, "-") == 0) - { - p = line.find (' '); - - string::size_type q (line.find ('=')); - if (q != string::npos && q < p) - p = q; - } - - string s1; - if (p != string::npos) - { - s1.assign (line, 0, p); - - // Skip leading whitespaces in the argument. - // - if (line[p] == '=') - ++p; - else - { - n = line.size (); - for (++p; p < n; ++p) - { - char c (line[p]); - if (c != ' ' && c != '\t' && c != '\r') - break; - } - } - } - else if (!skip_) - skip_ = (line == "--"); - - string s2 (line, p != string::npos ? p : 0); - - // If the string (which is an option value or argument) is - // wrapped in quotes, remove them. - // - n = s2.size (); - char cf (s2[0]), cl (s2[n - 1]); - - if (cf == '"' || cf == '\'' || cl == '"' || cl == '\'') - { - if (n == 1 || cf != cl) - throw unmatched_quote (s2); - - s2 = string (s2, 1, n - 2); - } - - if (!s1.empty ()) - { - // See if this is another file option. - // - const option_info* oi; - if (!skip_ && (oi = find (s1.c_str ()))) - { - if (s2.empty ()) - throw missing_value (oi->option); - - if (oi->search_func != 0) - { - string f (oi->search_func (s2.c_str (), oi->arg)); - if (!f.empty ()) - load (f); - } - else - { - // If the path of the file being parsed is not simple and the - // path of the file that needs to be loaded is relative, then - // complete the latter using the former as a base. - // -#ifndef _WIN32 - string::size_type p (file.find_last_of ('/')); - bool c (p != string::npos && s2[0] != '/'); -#else - string::size_type p (file.find_last_of ("/\\")); - bool c (p != string::npos && s2[1] != ':'); -#endif - if (c) - s2.insert (0, file, 0, p + 1); - - load (s2); - } - - continue; - } - - a.value = s1; - args_.push_back (a); - } - - a.value = s2; - args_.push_back (a); - } - } - - template - struct parser - { - static void - parse (X& x, bool& xs, scanner& s) - { - using namespace std; - - const char* o (s.next ()); - if (s.more ()) - { - string v (s.next ()); - istringstream is (v); - if (!(is >> x && is.peek () == istringstream::traits_type::eof ())) - throw invalid_value (o, v); - } - else - throw missing_value (o); - - xs = true; - } - }; - - template <> - struct parser - { - static void - parse (bool& x, bool& xs, scanner& s) - { - const char* o (s.next ()); - - if (s.more ()) - { - const char* v (s.next ()); - - if (std::strcmp (v, "1") == 0 || - std::strcmp (v, "true") == 0 || - std::strcmp (v, "TRUE") == 0 || - std::strcmp (v, "True") == 0) - x = true; - else if (std::strcmp (v, "0") == 0 || - std::strcmp (v, "false") == 0 || - std::strcmp (v, "FALSE") == 0 || - std::strcmp (v, "False") == 0) - x = false; - else - throw invalid_value (o, v); - } - else - throw missing_value (o); - - xs = true; - } - }; - - template <> - struct parser - { - static void - parse (std::string& x, bool& xs, scanner& s) - { - const char* o (s.next ()); - - if (s.more ()) - x = s.next (); - else - throw missing_value (o); - - xs = true; - } - }; - - template - struct parser > - { - static void - parse (std::pair& x, bool& xs, scanner& s) - { - x.second = s.position (); - parser::parse (x.first, xs, s); - } - }; - - template - struct parser > - { - static void - parse (std::vector& c, bool& xs, scanner& s) - { - X x; - bool dummy; - parser::parse (x, dummy, s); - c.push_back (x); - xs = true; - } - }; - - template - struct parser > - { - static void - parse (std::set& c, bool& xs, scanner& s) - { - X x; - bool dummy; - parser::parse (x, dummy, s); - c.insert (x); - xs = true; - } - }; - - template - struct parser > - { - static void - parse (std::map& m, bool& xs, scanner& s) - { - const char* o (s.next ()); - - if (s.more ()) - { - std::size_t pos (s.position ()); - std::string ov (s.next ()); - std::string::size_type p = ov.find ('='); - - K k = K (); - V v = V (); - std::string kstr (ov, 0, p); - std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ())); - - int ac (2); - char* av[] = - { - const_cast (o), - 0 - }; - - bool dummy; - if (!kstr.empty ()) - { - av[1] = const_cast (kstr.c_str ()); - argv_scanner s (0, ac, av, false, pos); - parser::parse (k, dummy, s); - } - - if (!vstr.empty ()) - { - av[1] = const_cast (vstr.c_str ()); - argv_scanner s (0, ac, av, false, pos); - parser::parse (v, dummy, s); - } - - m[k] = v; - } - else - throw missing_value (o); - - xs = true; - } - }; - - template - struct parser > - { - static void - parse (std::multimap& m, bool& xs, scanner& s) - { - const char* o (s.next ()); - - if (s.more ()) - { - std::size_t pos (s.position ()); - std::string ov (s.next ()); - std::string::size_type p = ov.find ('='); - - K k = K (); - V v = V (); - std::string kstr (ov, 0, p); - std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ())); - - int ac (2); - char* av[] = - { - const_cast (o), - 0 - }; - - bool dummy; - if (!kstr.empty ()) - { - av[1] = const_cast (kstr.c_str ()); - argv_scanner s (0, ac, av, false, pos); - parser::parse (k, dummy, s); - } - - if (!vstr.empty ()) - { - av[1] = const_cast (vstr.c_str ()); - argv_scanner s (0, ac, av, false, pos); - parser::parse (v, dummy, s); - } - - m.insert (typename std::multimap::value_type (k, v)); - } - else - throw missing_value (o); - - xs = true; - } - }; - - template - void - thunk (X& x, scanner& s) - { - parser::parse (x.*M, s); - } - - template - void - thunk (X& x, scanner& s) - { - s.next (); - x.*M = true; - } - - template - void - thunk (X& x, scanner& s) - { - parser::parse (x.*M, x.*S, s); - } - } - } - } -} - -#include - -namespace odb -{ - namespace mssql - { - namespace details - { - // options - // - - options:: - options () - : user_ (), - user_specified_ (false), - password_ (), - password_specified_ (false), - database_ (), - database_specified_ (false), - server_ (), - server_specified_ (false), - driver_ (), - driver_specified_ (false), - options_file_ (), - options_file_specified_ (false) - { - } - - options:: - options (int& argc, - char** argv, - bool erase, - ::odb::mssql::details::cli::unknown_mode opt, - ::odb::mssql::details::cli::unknown_mode arg) - : user_ (), - user_specified_ (false), - password_ (), - password_specified_ (false), - database_ (), - database_specified_ (false), - server_ (), - server_specified_ (false), - driver_ (), - driver_specified_ (false), - options_file_ (), - options_file_specified_ (false) - { - ::odb::mssql::details::cli::argv_scanner s (argc, argv, erase); - _parse (s, opt, arg); - } - - options:: - options (int start, - int& argc, - char** argv, - bool erase, - ::odb::mssql::details::cli::unknown_mode opt, - ::odb::mssql::details::cli::unknown_mode arg) - : user_ (), - user_specified_ (false), - password_ (), - password_specified_ (false), - database_ (), - database_specified_ (false), - server_ (), - server_specified_ (false), - driver_ (), - driver_specified_ (false), - options_file_ (), - options_file_specified_ (false) - { - ::odb::mssql::details::cli::argv_scanner s (start, argc, argv, erase); - _parse (s, opt, arg); - } - - options:: - options (int& argc, - char** argv, - int& end, - bool erase, - ::odb::mssql::details::cli::unknown_mode opt, - ::odb::mssql::details::cli::unknown_mode arg) - : user_ (), - user_specified_ (false), - password_ (), - password_specified_ (false), - database_ (), - database_specified_ (false), - server_ (), - server_specified_ (false), - driver_ (), - driver_specified_ (false), - options_file_ (), - options_file_specified_ (false) - { - ::odb::mssql::details::cli::argv_scanner s (argc, argv, erase); - _parse (s, opt, arg); - end = s.end (); - } - - options:: - options (int start, - int& argc, - char** argv, - int& end, - bool erase, - ::odb::mssql::details::cli::unknown_mode opt, - ::odb::mssql::details::cli::unknown_mode arg) - : user_ (), - user_specified_ (false), - password_ (), - password_specified_ (false), - database_ (), - database_specified_ (false), - server_ (), - server_specified_ (false), - driver_ (), - driver_specified_ (false), - options_file_ (), - options_file_specified_ (false) - { - ::odb::mssql::details::cli::argv_scanner s (start, argc, argv, erase); - _parse (s, opt, arg); - end = s.end (); - } - - options:: - options (::odb::mssql::details::cli::scanner& s, - ::odb::mssql::details::cli::unknown_mode opt, - ::odb::mssql::details::cli::unknown_mode arg) - : user_ (), - user_specified_ (false), - password_ (), - password_specified_ (false), - database_ (), - database_specified_ (false), - server_ (), - server_specified_ (false), - driver_ (), - driver_specified_ (false), - options_file_ (), - options_file_specified_ (false) - { - _parse (s, opt, arg); - } - - ::odb::mssql::details::cli::usage_para options:: - print_usage (::std::ostream& os, ::odb::mssql::details::cli::usage_para p) - { - CLI_POTENTIALLY_UNUSED (os); - - if (p != ::odb::mssql::details::cli::usage_para::none) - os << ::std::endl; - - os << "--user|-U SQL Server database user. If not specified, then Windows" << ::std::endl - << " authentication is used." << ::std::endl; - - os << std::endl - << "--password|-P SQL Server database password. Omit this option if the" << ::std::endl - << " user password is blank or Windows authentication is used." << ::std::endl; - - os << std::endl - << "--database|-d SQL Server database name. If not specified, then the" << ::std::endl - << " default database for this user is used." << ::std::endl; - - os << std::endl - << "--server|-S SQL Server instance address in the" << ::std::endl - << " [protocol:]host[\\instance][,port] format, where protocol" << ::std::endl - << " can be tcp (TCP/IP), lpc (shared memory), or np (named" << ::std::endl - << " pipe). If not specifid, then localhost is used." << ::std::endl; - - os << std::endl - << "--driver SQL Server Native Client ODBC driver name. If not" << ::std::endl - << " specified, then the latest available driver is used." << ::std::endl; - - os << std::endl - << "--options-file Read additional options from . Each option should" << ::std::endl - << " appear on a separate line optionally followed by space or" << ::std::endl - << " equal sign (=) and an option value. Empty lines and lines" << ::std::endl - << " starting with # are ignored." << ::std::endl; - - p = ::odb::mssql::details::cli::usage_para::option; - - return p; - } - - typedef - std::map - _cli_options_map; - - static _cli_options_map _cli_options_map_; - - struct _cli_options_map_init - { - _cli_options_map_init () - { - _cli_options_map_["--user"] = - &::odb::mssql::details::cli::thunk< options, std::string, &options::user_, - &options::user_specified_ >; - _cli_options_map_["-U"] = - &::odb::mssql::details::cli::thunk< options, std::string, &options::user_, - &options::user_specified_ >; - _cli_options_map_["--password"] = - &::odb::mssql::details::cli::thunk< options, std::string, &options::password_, - &options::password_specified_ >; - _cli_options_map_["-P"] = - &::odb::mssql::details::cli::thunk< options, std::string, &options::password_, - &options::password_specified_ >; - _cli_options_map_["--database"] = - &::odb::mssql::details::cli::thunk< options, std::string, &options::database_, - &options::database_specified_ >; - _cli_options_map_["-d"] = - &::odb::mssql::details::cli::thunk< options, std::string, &options::database_, - &options::database_specified_ >; - _cli_options_map_["--server"] = - &::odb::mssql::details::cli::thunk< options, std::string, &options::server_, - &options::server_specified_ >; - _cli_options_map_["-S"] = - &::odb::mssql::details::cli::thunk< options, std::string, &options::server_, - &options::server_specified_ >; - _cli_options_map_["--driver"] = - &::odb::mssql::details::cli::thunk< options, std::string, &options::driver_, - &options::driver_specified_ >; - _cli_options_map_["--options-file"] = - &::odb::mssql::details::cli::thunk< options, std::string, &options::options_file_, - &options::options_file_specified_ >; - } - }; - - static _cli_options_map_init _cli_options_map_init_; - - bool options:: - _parse (const char* o, ::odb::mssql::details::cli::scanner& s) - { - _cli_options_map::const_iterator i (_cli_options_map_.find (o)); - - if (i != _cli_options_map_.end ()) - { - (*(i->second)) (*this, s); - return true; - } - - return false; - } - - bool options:: - _parse (::odb::mssql::details::cli::scanner& s, - ::odb::mssql::details::cli::unknown_mode opt_mode, - ::odb::mssql::details::cli::unknown_mode arg_mode) - { - bool r = false; - bool opt = true; - - while (s.more ()) - { - const char* o = s.peek (); - - if (std::strcmp (o, "--") == 0) - { - opt = false; - s.skip (); - r = true; - continue; - } - - if (opt) - { - if (_parse (o, s)) - { - r = true; - continue; - } - - if (std::strncmp (o, "-", 1) == 0 && o[1] != '\0') - { - // Handle combined option values. - // - std::string co; - if (const char* v = std::strchr (o, '=')) - { - co.assign (o, 0, v - o); - ++v; - - int ac (2); - char* av[] = - { - const_cast (co.c_str ()), - const_cast (v) - }; - - ::odb::mssql::details::cli::argv_scanner ns (0, ac, av); - - if (_parse (co.c_str (), ns)) - { - // Parsed the option but not its value? - // - if (ns.end () != 2) - throw ::odb::mssql::details::cli::invalid_value (co, v); - - s.next (); - r = true; - continue; - } - else - { - // Set the unknown option and fall through. - // - o = co.c_str (); - } - } - - switch (opt_mode) - { - case ::odb::mssql::details::cli::unknown_mode::skip: - { - s.skip (); - r = true; - continue; - } - case ::odb::mssql::details::cli::unknown_mode::stop: - { - break; - } - case ::odb::mssql::details::cli::unknown_mode::fail: - { - throw ::odb::mssql::details::cli::unknown_option (o); - } - } - - break; - } - } - - switch (arg_mode) - { - case ::odb::mssql::details::cli::unknown_mode::skip: - { - s.skip (); - r = true; - continue; - } - case ::odb::mssql::details::cli::unknown_mode::stop: - { - break; - } - case ::odb::mssql::details::cli::unknown_mode::fail: - { - throw ::odb::mssql::details::cli::unknown_argument (o); - } - } - - break; - } - - return r; - } - } - } -} - -// Begin epilogue. -// -// -// End epilogue. - diff --git a/odb/mssql/details/pregenerated/odb/mssql/details/options.hxx b/odb/mssql/details/pregenerated/odb/mssql/details/options.hxx deleted file mode 100644 index 104395b..0000000 --- a/odb/mssql/details/pregenerated/odb/mssql/details/options.hxx +++ /dev/null @@ -1,562 +0,0 @@ -// -*- C++ -*- -// -// This file was generated by CLI, a command line interface -// compiler for C++. -// - -#ifndef LIBODB_MSSQL_DETAILS_OPTIONS_HXX -#define LIBODB_MSSQL_DETAILS_OPTIONS_HXX - -// Begin prologue. -// -// -// End prologue. - -#include -#include -#include -#include -#include -#include - -#ifndef CLI_POTENTIALLY_UNUSED -# if defined(_MSC_VER) || defined(__xlC__) -# define CLI_POTENTIALLY_UNUSED(x) (void*)&x -# else -# define CLI_POTENTIALLY_UNUSED(x) (void)x -# endif -#endif - -namespace odb -{ - namespace mssql - { - namespace details - { - namespace cli - { - class usage_para - { - public: - enum value - { - none, - text, - option - }; - - usage_para (value); - - operator value () const - { - return v_; - } - - private: - value v_; - }; - - class unknown_mode - { - public: - enum value - { - skip, - stop, - fail - }; - - unknown_mode (value); - - operator value () const - { - return v_; - } - - private: - value v_; - }; - - // Exceptions. - // - - class exception: public std::exception - { - public: - virtual void - print (::std::ostream&) const = 0; - }; - - ::std::ostream& - operator<< (::std::ostream&, const exception&); - - class unknown_option: public exception - { - public: - virtual - ~unknown_option () throw (); - - unknown_option (const std::string& option); - - const std::string& - option () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string option_; - }; - - class unknown_argument: public exception - { - public: - virtual - ~unknown_argument () throw (); - - unknown_argument (const std::string& argument); - - const std::string& - argument () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string argument_; - }; - - class missing_value: public exception - { - public: - virtual - ~missing_value () throw (); - - missing_value (const std::string& option); - - const std::string& - option () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string option_; - }; - - class invalid_value: public exception - { - public: - virtual - ~invalid_value () throw (); - - invalid_value (const std::string& option, - const std::string& value, - const std::string& message = std::string ()); - - const std::string& - option () const; - - const std::string& - value () const; - - const std::string& - message () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string option_; - std::string value_; - std::string message_; - }; - - class eos_reached: public exception - { - public: - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - }; - - class file_io_failure: public exception - { - public: - virtual - ~file_io_failure () throw (); - - file_io_failure (const std::string& file); - - const std::string& - file () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string file_; - }; - - class unmatched_quote: public exception - { - public: - virtual - ~unmatched_quote () throw (); - - unmatched_quote (const std::string& argument); - - const std::string& - argument () const; - - virtual void - print (::std::ostream&) const; - - virtual const char* - what () const throw (); - - private: - std::string argument_; - }; - - // Command line argument scanner interface. - // - // The values returned by next() are guaranteed to be valid - // for the two previous arguments up until a call to a third - // peek() or next(). - // - // The position() function returns a monotonically-increasing - // number which, if stored, can later be used to determine the - // relative position of the argument returned by the following - // call to next(). Note that if multiple scanners are used to - // extract arguments from multiple sources, then the end - // position of the previous scanner should be used as the - // start position of the next. - // - class scanner - { - public: - virtual - ~scanner (); - - virtual bool - more () = 0; - - virtual const char* - peek () = 0; - - virtual const char* - next () = 0; - - virtual void - skip () = 0; - - virtual std::size_t - position () = 0; - }; - - class argv_scanner: public scanner - { - public: - argv_scanner (int& argc, - char** argv, - bool erase = false, - std::size_t start_position = 0); - - argv_scanner (int start, - int& argc, - char** argv, - bool erase = false, - std::size_t start_position = 0); - - int - end () const; - - virtual bool - more (); - - virtual const char* - peek (); - - virtual const char* - next (); - - virtual void - skip (); - - virtual std::size_t - position (); - - protected: - std::size_t start_position_; - int i_; - int& argc_; - char** argv_; - bool erase_; - }; - - class argv_file_scanner: public argv_scanner - { - public: - argv_file_scanner (int& argc, - char** argv, - const std::string& option, - bool erase = false, - std::size_t start_position = 0); - - argv_file_scanner (int start, - int& argc, - char** argv, - const std::string& option, - bool erase = false, - std::size_t start_position = 0); - - argv_file_scanner (const std::string& file, - const std::string& option, - std::size_t start_position = 0); - - struct option_info - { - // If search_func is not NULL, it is called, with the arg - // value as the second argument, to locate the options file. - // If it returns an empty string, then the file is ignored. - // - const char* option; - std::string (*search_func) (const char*, void* arg); - void* arg; - }; - - argv_file_scanner (int& argc, - char** argv, - const option_info* options, - std::size_t options_count, - bool erase = false, - std::size_t start_position = 0); - - argv_file_scanner (int start, - int& argc, - char** argv, - const option_info* options, - std::size_t options_count, - bool erase = false, - std::size_t start_position = 0); - - argv_file_scanner (const std::string& file, - const option_info* options = 0, - std::size_t options_count = 0, - std::size_t start_position = 0); - - virtual bool - more (); - - virtual const char* - peek (); - - virtual const char* - next (); - - virtual void - skip (); - - virtual std::size_t - position (); - - // Return the file path if the peeked at argument came from a file and - // the empty string otherwise. The reference is guaranteed to be valid - // till the end of the scanner lifetime. - // - const std::string& - peek_file (); - - // Return the 1-based line number if the peeked at argument came from - // a file and zero otherwise. - // - std::size_t - peek_line (); - - private: - const option_info* - find (const char*) const; - - void - load (const std::string& file); - - typedef argv_scanner base; - - const std::string option_; - option_info option_info_; - const option_info* options_; - std::size_t options_count_; - - struct arg - { - std::string value; - const std::string* file; - std::size_t line; - }; - - std::deque args_; - std::list files_; - - // Circular buffer of two arguments. - // - std::string hold_[2]; - std::size_t i_; - - bool skip_; - - static int zero_argc_; - static std::string empty_string_; - }; - - template - struct parser; - } - } - } -} - -#include - -namespace odb -{ - namespace mssql - { - namespace details - { - class options - { - public: - options (); - - options (int& argc, - char** argv, - bool erase = false, - ::odb::mssql::details::cli::unknown_mode option = ::odb::mssql::details::cli::unknown_mode::fail, - ::odb::mssql::details::cli::unknown_mode argument = ::odb::mssql::details::cli::unknown_mode::stop); - - options (int start, - int& argc, - char** argv, - bool erase = false, - ::odb::mssql::details::cli::unknown_mode option = ::odb::mssql::details::cli::unknown_mode::fail, - ::odb::mssql::details::cli::unknown_mode argument = ::odb::mssql::details::cli::unknown_mode::stop); - - options (int& argc, - char** argv, - int& end, - bool erase = false, - ::odb::mssql::details::cli::unknown_mode option = ::odb::mssql::details::cli::unknown_mode::fail, - ::odb::mssql::details::cli::unknown_mode argument = ::odb::mssql::details::cli::unknown_mode::stop); - - options (int start, - int& argc, - char** argv, - int& end, - bool erase = false, - ::odb::mssql::details::cli::unknown_mode option = ::odb::mssql::details::cli::unknown_mode::fail, - ::odb::mssql::details::cli::unknown_mode argument = ::odb::mssql::details::cli::unknown_mode::stop); - - options (::odb::mssql::details::cli::scanner&, - ::odb::mssql::details::cli::unknown_mode option = ::odb::mssql::details::cli::unknown_mode::fail, - ::odb::mssql::details::cli::unknown_mode argument = ::odb::mssql::details::cli::unknown_mode::stop); - - // Option accessors. - // - const std::string& - user () const; - - bool - user_specified () const; - - const std::string& - password () const; - - bool - password_specified () const; - - const std::string& - database () const; - - bool - database_specified () const; - - const std::string& - server () const; - - bool - server_specified () const; - - const std::string& - driver () const; - - bool - driver_specified () const; - - const std::string& - options_file () const; - - bool - options_file_specified () const; - - // Print usage information. - // - static ::odb::mssql::details::cli::usage_para - print_usage (::std::ostream&, - ::odb::mssql::details::cli::usage_para = ::odb::mssql::details::cli::usage_para::none); - - // Implementation details. - // - protected: - bool - _parse (const char*, ::odb::mssql::details::cli::scanner&); - - private: - bool - _parse (::odb::mssql::details::cli::scanner&, - ::odb::mssql::details::cli::unknown_mode option, - ::odb::mssql::details::cli::unknown_mode argument); - - public: - std::string user_; - bool user_specified_; - std::string password_; - bool password_specified_; - std::string database_; - bool database_specified_; - std::string server_; - bool server_specified_; - std::string driver_; - bool driver_specified_; - std::string options_file_; - bool options_file_specified_; - }; - } - } -} - -#include - -// Begin epilogue. -// -// -// End epilogue. - -#endif // LIBODB_MSSQL_DETAILS_OPTIONS_HXX diff --git a/odb/mssql/details/pregenerated/odb/mssql/details/options.ixx b/odb/mssql/details/pregenerated/odb/mssql/details/options.ixx deleted file mode 100644 index a406dc4..0000000 --- a/odb/mssql/details/pregenerated/odb/mssql/details/options.ixx +++ /dev/null @@ -1,372 +0,0 @@ -// -*- C++ -*- -// -// This file was generated by CLI, a command line interface -// compiler for C++. -// - -// Begin prologue. -// -// -// End prologue. - -#include - -namespace odb -{ - namespace mssql - { - namespace details - { - namespace cli - { - // usage_para - // - inline usage_para:: - usage_para (value v) - : v_ (v) - { - } - - // unknown_mode - // - inline unknown_mode:: - unknown_mode (value v) - : v_ (v) - { - } - - // exception - // - inline ::std::ostream& - operator<< (::std::ostream& os, const exception& e) - { - e.print (os); - return os; - } - - // unknown_option - // - inline unknown_option:: - unknown_option (const std::string& option) - : option_ (option) - { - } - - inline const std::string& unknown_option:: - option () const - { - return option_; - } - - // unknown_argument - // - inline unknown_argument:: - unknown_argument (const std::string& argument) - : argument_ (argument) - { - } - - inline const std::string& unknown_argument:: - argument () const - { - return argument_; - } - - // missing_value - // - inline missing_value:: - missing_value (const std::string& option) - : option_ (option) - { - } - - inline const std::string& missing_value:: - option () const - { - return option_; - } - - // invalid_value - // - inline invalid_value:: - invalid_value (const std::string& option, - const std::string& value, - const std::string& message) - : option_ (option), - value_ (value), - message_ (message) - { - } - - inline const std::string& invalid_value:: - option () const - { - return option_; - } - - inline const std::string& invalid_value:: - value () const - { - return value_; - } - - inline const std::string& invalid_value:: - message () const - { - return message_; - } - - // file_io_failure - // - inline file_io_failure:: - file_io_failure (const std::string& file) - : file_ (file) - { - } - - inline const std::string& file_io_failure:: - file () const - { - return file_; - } - - // unmatched_quote - // - inline unmatched_quote:: - unmatched_quote (const std::string& argument) - : argument_ (argument) - { - } - - inline const std::string& unmatched_quote:: - argument () const - { - return argument_; - } - - // argv_scanner - // - inline argv_scanner:: - argv_scanner (int& argc, - char** argv, - bool erase, - std::size_t sp) - : start_position_ (sp + 1), - i_ (1), - argc_ (argc), - argv_ (argv), - erase_ (erase) - { - } - - inline argv_scanner:: - argv_scanner (int start, - int& argc, - char** argv, - bool erase, - std::size_t sp) - : start_position_ (sp + static_cast (start)), - i_ (start), - argc_ (argc), - argv_ (argv), - erase_ (erase) - { - } - - inline int argv_scanner:: - end () const - { - return i_; - } - - // argv_file_scanner - // - inline argv_file_scanner:: - argv_file_scanner (int& argc, - char** argv, - const std::string& option, - bool erase, - std::size_t sp) - : argv_scanner (argc, argv, erase, sp), - option_ (option), - options_ (&option_info_), - options_count_ (1), - i_ (1), - skip_ (false) - { - option_info_.option = option_.c_str (); - option_info_.search_func = 0; - } - - inline argv_file_scanner:: - argv_file_scanner (int start, - int& argc, - char** argv, - const std::string& option, - bool erase, - std::size_t sp) - : argv_scanner (start, argc, argv, erase, sp), - option_ (option), - options_ (&option_info_), - options_count_ (1), - i_ (1), - skip_ (false) - { - option_info_.option = option_.c_str (); - option_info_.search_func = 0; - } - - inline argv_file_scanner:: - argv_file_scanner (const std::string& file, - const std::string& option, - std::size_t sp) - : argv_scanner (0, zero_argc_, 0, sp), - option_ (option), - options_ (&option_info_), - options_count_ (1), - i_ (1), - skip_ (false) - { - option_info_.option = option_.c_str (); - option_info_.search_func = 0; - - load (file); - } - - inline argv_file_scanner:: - argv_file_scanner (int& argc, - char** argv, - const option_info* options, - std::size_t options_count, - bool erase, - std::size_t sp) - : argv_scanner (argc, argv, erase, sp), - options_ (options), - options_count_ (options_count), - i_ (1), - skip_ (false) - { - } - - inline argv_file_scanner:: - argv_file_scanner (int start, - int& argc, - char** argv, - const option_info* options, - std::size_t options_count, - bool erase, - std::size_t sp) - : argv_scanner (start, argc, argv, erase, sp), - options_ (options), - options_count_ (options_count), - i_ (1), - skip_ (false) - { - } - - inline argv_file_scanner:: - argv_file_scanner (const std::string& file, - const option_info* options, - std::size_t options_count, - std::size_t sp) - : argv_scanner (0, zero_argc_, 0, sp), - options_ (options), - options_count_ (options_count), - i_ (1), - skip_ (false) - { - load (file); - } - } - } - } -} - -namespace odb -{ - namespace mssql - { - namespace details - { - // options - // - - inline const std::string& options:: - user () const - { - return this->user_; - } - - inline bool options:: - user_specified () const - { - return this->user_specified_; - } - - inline const std::string& options:: - password () const - { - return this->password_; - } - - inline bool options:: - password_specified () const - { - return this->password_specified_; - } - - inline const std::string& options:: - database () const - { - return this->database_; - } - - inline bool options:: - database_specified () const - { - return this->database_specified_; - } - - inline const std::string& options:: - server () const - { - return this->server_; - } - - inline bool options:: - server_specified () const - { - return this->server_specified_; - } - - inline const std::string& options:: - driver () const - { - return this->driver_; - } - - inline bool options:: - driver_specified () const - { - return this->driver_specified_; - } - - inline const std::string& options:: - options_file () const - { - return this->options_file_; - } - - inline bool options:: - options_file_specified () const - { - return this->options_file_specified_; - } - } - } -} - -// Begin epilogue. -// -// -// End epilogue. diff --git a/odb/mssql/error.cxx b/odb/mssql/error.cxx deleted file mode 100644 index 897d415..0000000 --- a/odb/mssql/error.cxx +++ /dev/null @@ -1,273 +0,0 @@ -// file : odb/mssql/error.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include -#include // std::strlen - -#include -#include -#include -#include - -using namespace std; - -namespace odb -{ - namespace mssql - { - static void - translate_error (SQLRETURN r, - SQLHANDLE h, - SQLSMALLINT htype, - connection* conn, - bool end_tran, - size_t pos, - multiple_exceptions* mex) - { - // First see if we have one of the errors indicated via the - // return error code. - // - switch (r) - { - case SQL_STILL_EXECUTING: - { - throw database_exception (0, "?????", "statement still executing"); - break; - } - case SQL_NEED_DATA: - case SQL_NO_DATA: -#if ODBCVER >= 0x0380 - case SQL_PARAM_DATA_AVAILABLE: -#endif - { - throw database_exception ( - 0, "?????", "unhandled SQL_*_DATA condition"); - break; - } - case SQL_INVALID_HANDLE: - { - throw database_exception (0, "?????", "invalid handle"); - break; - } - } - - // Otherwise the diagnostics is stored in the handle. - // - char sqlstate[SQL_SQLSTATE_SIZE + 1]; - SQLINTEGER native_code; // Will be 0 if no natve code. - char msg[512]; // Will be truncated if doesn't fit. - SQLSMALLINT msg_size; - - // We need to translate certain sqlstate codes to special exceptions, - // such as deadlock, timeout, etc. The problem is we can have multiple - // records potentially with different sqlstate codes. If we have both, - // say, a deadlock code and some other code, then we should probably - // throw database_exception, which is more severe. To implement this - // we are going to pre-scan the records looking for the codes we are - // interested in. If in the process we see any other code, then we - // stop and go ahead to prepare and throw database_exception. - // - enum code - { - code_none, - code_deadlock, - code_timeout, - code_connection_lost - }; - - code c (code_none); - - for (SQLSMALLINT i (1);; ++i) - { - r = SQLGetDiagRecA (htype, - h, - i, - (SQLCHAR*) sqlstate, - &native_code, - 0, - 0, - &msg_size); - - if (r == SQL_NO_DATA) - break; - else if (SQL_SUCCEEDED (r)) - { - code nc; - string s (sqlstate); - - if (s == "40001") // Serialization failure (native code 1205). - nc = code_deadlock; - else if (s == "HYT00") // Timeout expired. - nc = code_timeout; - else if (s == "HYT01") // Connection timeout expired. - { - nc = code_timeout; - - if (conn != 0) - conn->mark_failed (); - } - else if (s == "08S01") // Link failure. - { - nc = code_connection_lost; - - if (conn != 0) - conn->mark_failed (); - } - else if (s == "01000") // General warning. - continue; - else - { - c = code_none; - break; - } - - // If a call to SQLEndTran() fails, then the connection is - // put into the so called "suspended state" and should be - // disconnected unless we know the transaction was rolled - // back. See SQLEndTran() documentation for details. - // - if (end_tran && - s != "25S03" && // Transaction is rolled back. - s != "40001" && // Serialization failure. - s != "40002" && // Integrity constraint. - s != "HYC00") // Optional feature not implemented. - conn->mark_failed (); - - if (c != code_none && c != nc) - { - // Several different codes. - // - c = code_none; - break; - } - - c = nc; - } - else - { - c = code_none; - break; - } - } - - switch (c) - { - case code_deadlock: - throw deadlock (); - case code_timeout: - throw timeout (); - case code_connection_lost: - throw connection_lost (); - case code_none: - break; - } - - // Some other error code. Prepare database_exception. - // - database_exception e; - - for (SQLSMALLINT i (1);; ++i) - { - // If this is for a batch, filter out based on row association. - // Here we only ignore records that have the associated row - // number and this number doesn't match ours. In particular, - // this means that all the un-associated records which will be - // duplicated for all the failed rows, which seems like the - // correct thing to do. - // - if (mex != 0) - { - SQLLEN n; - r = SQLGetDiagField (htype, - h, - i, - SQL_DIAG_ROW_NUMBER, - &n, - 0, - 0); - - if (r == SQL_NO_DATA) - break; - else if (SQL_SUCCEEDED (r) && - n != SQL_NO_ROW_NUMBER && - n != SQL_ROW_NUMBER_UNKNOWN && - n != static_cast (pos + 1)) // 1-based - continue; - } - - r = SQLGetDiagRecA (htype, - h, - i, - (SQLCHAR*) sqlstate, - &native_code, - (SQLCHAR*) msg, - sizeof (msg), - &msg_size); - - if (r == SQL_NO_DATA) - break; - else if (SQL_SUCCEEDED (r)) - { - if (conn != 0) - { - string s (sqlstate); - - if (s == "08S01" || // Link failure. - s == "HYT01" || // Connection timeout. - (end_tran && - s != "25S03" && - s != "40001" && - s != "40002" && - s != "HYC00")) - conn->mark_failed (); - } - - // Get rid of a trailing newline if there is one. - // - size_t n (strlen (msg)); - if (n != 0 && msg[n - 1] == '\n') - msg[n - 1] = '\0'; - - e.append (native_code, sqlstate, msg); - } - else - e.append (0, "?????", "unable to extract information for this " - "diagnostic record"); - } - - if (e.size () == 0) - e.append (0, "?????", "no diagnostic record (using wrong handle?)"); - - if (mex == 0) - throw e; - else - // It could be that some of these errors are fatal. I guess we - // will just have to learn from experience which ones are. The - // client code can always treat specific error codes as fatal. - // - mex->insert (pos, e); - } - - void - translate_error (SQLRETURN r, connection& c, bool end_tran) - { - translate_error (r, c.handle (), SQL_HANDLE_DBC, &c, end_tran, 0, 0); - } - - void - translate_error (SQLRETURN r, - connection& c, - const auto_handle& h, - size_t pos, - multiple_exceptions* mex) - { - translate_error (r, h, SQL_HANDLE_STMT, &c, false, pos, mex); - } - - void - translate_error (SQLRETURN r, SQLHANDLE h, SQLSMALLINT htype) - { - translate_error (r, h, htype, 0, false, 0, 0); - } - } -} diff --git a/odb/mssql/error.hxx b/odb/mssql/error.hxx deleted file mode 100644 index cb8cc7c..0000000 --- a/odb/mssql/error.hxx +++ /dev/null @@ -1,40 +0,0 @@ -// file : odb/mssql/error.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_ERROR_HXX -#define ODB_MSSQL_ERROR_HXX - -#include -#include // std::size_t - -#include -#include -#include // connection, multiple_exceptions -#include - -#include - -namespace odb -{ - namespace mssql - { - // Translate ODBC error given a handle and throw (or return, in case - // multiple_exceptions is not NULL) an appropriate exception. - // - LIBODB_MSSQL_EXPORT void - translate_error (SQLRETURN, connection&, bool end_tran = false); - - LIBODB_MSSQL_EXPORT void - translate_error (SQLRETURN, - connection&, - const auto_handle&, - std::size_t pos = 0, multiple_exceptions* = 0); - - LIBODB_MSSQL_EXPORT void - translate_error (SQLRETURN, SQLHANDLE, SQLSMALLINT htype); - } -} - -#include - -#endif // ODB_MSSQL_ERROR_HXX diff --git a/odb/mssql/exceptions.cxx b/odb/mssql/exceptions.cxx deleted file mode 100644 index 606678d..0000000 --- a/odb/mssql/exceptions.cxx +++ /dev/null @@ -1,109 +0,0 @@ -// file : odb/mssql/exceptions.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -#include - -using namespace std; - -namespace odb -{ - namespace mssql - { - // - // database_exception - // - - database_exception::record:: - record (SQLINTEGER e, const string& s, const string& m) - : error_ (e), sqlstate_ (s), message_ (m) - { - } - - database_exception:: - ~database_exception () ODB_NOTHROW_NOEXCEPT - { - } - - database_exception:: - database_exception () - { - } - - database_exception:: - database_exception (SQLINTEGER e, const string& s, const string& m) - { - append (e, s, m); - } - - void database_exception:: - append (SQLINTEGER e, const string& s, const string& m) - { - records_.push_back (record (e, s, m)); - - if (!what_.empty ()) - what_ += '\n'; - - ostringstream ostr; - ostr << e << " (" << s << "): " << m; - what_ += ostr.str (); - } - - const char* database_exception:: - what () const ODB_NOTHROW_NOEXCEPT - { - return what_.c_str (); - } - - database_exception* database_exception:: - clone () const - { - return new database_exception (*this); - } - - // - // cli_exception - // - - cli_exception:: - cli_exception (const string& what) - : what_ (what) - { - } - - cli_exception:: - ~cli_exception () ODB_NOTHROW_NOEXCEPT - { - } - - const char* cli_exception:: - what () const ODB_NOTHROW_NOEXCEPT - { - return what_.c_str (); - } - - cli_exception* cli_exception:: - clone () const - { - return new cli_exception (*this); - } - - // - // long_data_reload - // - - const char* long_data_reload:: - what () const ODB_NOTHROW_NOEXCEPT - { - return "attempt to re-load object or view with long data " - "from query result"; - } - - long_data_reload* long_data_reload:: - clone () const - { - return new long_data_reload (*this); - } - } -} diff --git a/odb/mssql/exceptions.hxx b/odb/mssql/exceptions.hxx deleted file mode 100644 index 5240d8d..0000000 --- a/odb/mssql/exceptions.hxx +++ /dev/null @@ -1,138 +0,0 @@ -// file : odb/mssql/exceptions.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_EXCEPTIONS_HXX -#define ODB_MSSQL_EXCEPTIONS_HXX - -#include - -#include -#include - -#include -#include // ODB_NOTHROW_NOEXCEPT - -#include -#include -#include -#include - -namespace odb -{ - namespace mssql - { - struct LIBODB_MSSQL_EXPORT database_exception: odb::database_exception - { - struct record - { - record (SQLINTEGER error, - const std::string& sqlstate, - const std::string& message); - - SQLINTEGER - error () const - { - return error_; - } - - const std::string& - sqlstate () const - { - return sqlstate_; - } - - const std::string& - message () const - { - return message_; - } - - private: - SQLINTEGER error_; - std::string sqlstate_; - std::string message_; - }; - - typedef std::vector records; - - typedef records::size_type size_type; - typedef records::const_iterator iterator; - - iterator - begin () const - { - return records_.begin (); - } - - iterator - end () const - { - return records_.end (); - } - - size_type - size () const - { - return records_.size (); - } - - virtual const char* - what () const ODB_NOTHROW_NOEXCEPT; - - virtual database_exception* - clone () const; - - public: - ~database_exception () ODB_NOTHROW_NOEXCEPT; - - database_exception (); - database_exception (SQLINTEGER error, - const std::string& sqlstate, - const std::string& message); - - void - append (SQLINTEGER error, - const std::string& sqlstate, - const std::string& message); - - private: - records records_; - std::string what_; - }; - - struct LIBODB_MSSQL_EXPORT cli_exception: odb::exception - { - cli_exception (const std::string& what); - ~cli_exception () ODB_NOTHROW_NOEXCEPT; - - virtual const char* - what () const ODB_NOTHROW_NOEXCEPT; - - virtual cli_exception* - clone () const; - - private: - std::string what_; - }; - - struct LIBODB_MSSQL_EXPORT long_data_reload: odb::exception - { - virtual const char* - what () const ODB_NOTHROW_NOEXCEPT; - - virtual long_data_reload* - clone () const; - }; - - namespace core - { - using mssql::database_exception; - using mssql::cli_exception; - using mssql::long_data_reload; - } - } -} - -#include - -#endif // ODB_MSSQL_EXCEPTIONS_HXX diff --git a/odb/mssql/forward.hxx b/odb/mssql/forward.hxx deleted file mode 100644 index 4f32b22..0000000 --- a/odb/mssql/forward.hxx +++ /dev/null @@ -1,91 +0,0 @@ -// file : odb/mssql/forward.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_FORWARD_HXX -#define ODB_MSSQL_FORWARD_HXX - -#include - -#include - -namespace odb -{ - namespace mssql - { - namespace core - { - using namespace odb::common; - } - - // - // - class database; - class connection; - typedef details::shared_ptr connection_ptr; - class connection_factory; - class statement; - class transaction; - class tracer; - - namespace core - { - using mssql::database; - using mssql::connection; - using mssql::connection_ptr; - using mssql::transaction; - using mssql::statement; - } - - // Implementation details. - // - enum statement_kind - { - statement_select, - statement_insert, - statement_update, - statement_delete - }; - - class binding; - class select_statement; - - template - class object_statements; - - template - class polymorphic_root_object_statements; - - template - class polymorphic_derived_object_statements; - - template - class no_id_object_statements; - - template - class view_statements; - - template - class container_statements; - - template - class smart_container_statements; - - template - class section_statements; - - class query_base; - } - - namespace details - { - template <> - struct counter_type - { - typedef shared_base counter; - }; - } -} - -#include - -#endif // ODB_MSSQL_FORWARD_HXX diff --git a/odb/mssql/libodb-mssql-vc10.vcxproj b/odb/mssql/libodb-mssql-vc10.vcxproj deleted file mode 100644 index e36d7ce..0000000 --- a/odb/mssql/libodb-mssql-vc10.vcxproj +++ /dev/null @@ -1,174 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13} - Win32Proj - libodb-mssql - - - - DynamicLibrary - true - Unicode - - - DynamicLibrary - true - Unicode - - - DynamicLibrary - false - true - Unicode - - - DynamicLibrary - false - true - Unicode - - - - - - - - - - - - - - - - - - - true - ..\..\bin\ - odb-mssql-d-__value__(interface_version)-vc10 - - - true - ..\..\bin64\ - odb-mssql-d-__value__(interface_version)-vc10 - - - false - ..\..\bin\ - odb-mssql-__value__(interface_version)-vc10 - - - false - ..\..\bin64\ - odb-mssql-__value__(interface_version)-vc10 - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - - - odb-d.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - $(TargetPath) - ..\..\lib\odb-mssql-d.lib - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - - - odb-d.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - $(TargetPath) - ..\..\lib64\odb-mssql-d.lib - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - - - odb.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - true - true - $(TargetPath) - ..\..\lib\odb-mssql.lib - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - - - odb.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - true - true - $(TargetPath) - ..\..\lib64\odb-mssql.lib - - - -__header_entries__(headers) - - -__source_entries__(sources) - - - - - diff --git a/odb/mssql/libodb-mssql-vc10.vcxproj.filters b/odb/mssql/libodb-mssql-vc10.vcxproj.filters deleted file mode 100644 index 6c33a96..0000000 --- a/odb/mssql/libodb-mssql-vc10.vcxproj.filters +++ /dev/null @@ -1,19 +0,0 @@ - - - - - {DAC90661-7ECF-461C-9F48-0F11F46D656B} - cxx - - - {7AF464A2-7C7D-45E7-8265-7468885489FD} - h;hxx;ixx;txx - - - -__header_filter_entries__(headers) - - -__source_filter_entries__(sources) - - diff --git a/odb/mssql/libodb-mssql-vc11.vcxproj b/odb/mssql/libodb-mssql-vc11.vcxproj deleted file mode 100644 index 873431e..0000000 --- a/odb/mssql/libodb-mssql-vc11.vcxproj +++ /dev/null @@ -1,178 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13} - Win32Proj - libodb-mssql - - - - DynamicLibrary - true - v110 - Unicode - - - DynamicLibrary - true - v110 - Unicode - - - DynamicLibrary - false - v110 - true - Unicode - - - DynamicLibrary - false - v110 - true - Unicode - - - - - - - - - - - - - - - - - - - true - ..\..\bin\ - odb-mssql-d-__value__(interface_version)-vc11 - - - true - ..\..\bin64\ - odb-mssql-d-__value__(interface_version)-vc11 - - - false - ..\..\bin\ - odb-mssql-__value__(interface_version)-vc11 - - - false - ..\..\bin64\ - odb-mssql-__value__(interface_version)-vc11 - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - - - odb-d.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - $(TargetPath) - ..\..\lib\odb-mssql-d.lib - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - - - odb-d.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - $(TargetPath) - ..\..\lib64\odb-mssql-d.lib - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - - - odb.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - true - true - $(TargetPath) - ..\..\lib\odb-mssql.lib - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - - - odb.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - true - true - $(TargetPath) - ..\..\lib64\odb-mssql.lib - - - -__header_entries__(headers) - - -__source_entries__(sources) - - - - - diff --git a/odb/mssql/libodb-mssql-vc11.vcxproj.filters b/odb/mssql/libodb-mssql-vc11.vcxproj.filters deleted file mode 100644 index 6c33a96..0000000 --- a/odb/mssql/libodb-mssql-vc11.vcxproj.filters +++ /dev/null @@ -1,19 +0,0 @@ - - - - - {DAC90661-7ECF-461C-9F48-0F11F46D656B} - cxx - - - {7AF464A2-7C7D-45E7-8265-7468885489FD} - h;hxx;ixx;txx - - - -__header_filter_entries__(headers) - - -__source_filter_entries__(sources) - - diff --git a/odb/mssql/libodb-mssql-vc12.vcxproj b/odb/mssql/libodb-mssql-vc12.vcxproj deleted file mode 100644 index 13f2666..0000000 --- a/odb/mssql/libodb-mssql-vc12.vcxproj +++ /dev/null @@ -1,182 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {E1AB8673-9D52-4984-AF83-BCB5BC97BB13} - Win32Proj - libodb-mssql - - - - DynamicLibrary - true - v120 - Unicode - - - DynamicLibrary - true - v120 - Unicode - - - DynamicLibrary - false - v120 - true - Unicode - - - DynamicLibrary - false - v120 - true - Unicode - - - - - - - - - - - - - - - - - - - true - ..\..\bin\ - odb-mssql-d-__value__(interface_version)-vc12 - - - true - ..\..\bin64\ - odb-mssql-d-__value__(interface_version)-vc12 - - - false - ..\..\bin\ - odb-mssql-__value__(interface_version)-vc12 - - - false - ..\..\bin64\ - odb-mssql-__value__(interface_version)-vc12 - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - true - - - odb-d.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - $(TargetPath) - ..\..\lib\odb-mssql-d.lib - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - true - - - odb-d.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - $(TargetPath) - ..\..\lib64\odb-mssql-d.lib - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - true - - - odb.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - true - true - $(TargetPath) - ..\..\lib\odb-mssql.lib - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBODB_MSSQL_DYNAMIC_LIB;%(PreprocessorDefinitions) - ..\.. - 4355;4800;4290;4251;4267;%(DisableSpecificWarnings) - true - - - odb.lib;odbc32.lib;%(AdditionalDependencies) - Windows - true - true - true - $(TargetPath) - ..\..\lib64\odb-mssql.lib - - - -__header_entries__(headers) - - -__source_entries__(sources) - - - - - diff --git a/odb/mssql/libodb-mssql-vc12.vcxproj.filters b/odb/mssql/libodb-mssql-vc12.vcxproj.filters deleted file mode 100644 index 6c33a96..0000000 --- a/odb/mssql/libodb-mssql-vc12.vcxproj.filters +++ /dev/null @@ -1,19 +0,0 @@ - - - - - {DAC90661-7ECF-461C-9F48-0F11F46D656B} - cxx - - - {7AF464A2-7C7D-45E7-8265-7468885489FD} - h;hxx;ixx;txx - - - -__header_filter_entries__(headers) - - -__source_filter_entries__(sources) - - diff --git a/odb/mssql/libodb-mssql-vc8.vcproj b/odb/mssql/libodb-mssql-vc8.vcproj deleted file mode 100644 index 5fadaa9..0000000 --- a/odb/mssql/libodb-mssql-vc8.vcproj +++ /dev/null @@ -1,352 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -__source_entries__(sources) - - -__file_entries__(headers) - - - - - diff --git a/odb/mssql/libodb-mssql-vc9.vcproj b/odb/mssql/libodb-mssql-vc9.vcproj deleted file mode 100644 index 918d73a..0000000 --- a/odb/mssql/libodb-mssql-vc9.vcproj +++ /dev/null @@ -1,359 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -__source_entries__(sources) - - -__file_entries__(headers) - - - - - diff --git a/odb/mssql/makefile b/odb/mssql/makefile deleted file mode 100644 index 8cf46a8..0000000 --- a/odb/mssql/makefile +++ /dev/null @@ -1,156 +0,0 @@ -# file : odb/mssql/makefile -# license : ODB NCUEL; see accompanying LICENSE file - -include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make - -cxx := \ -auto-handle.cxx \ -connection.cxx \ -connection-factory.cxx \ -database.cxx \ -error.cxx \ -exceptions.cxx \ -prepared-query.cxx \ -query.cxx \ -query-dynamic.cxx \ -query-const-expr.cxx \ -simple-object-statements.cxx \ -statement.cxx \ -statement-processing.cxx \ -statements-base.cxx \ -tracer.cxx \ -traits.cxx \ -transaction.cxx \ -transaction-impl.cxx - - -cli_tun := details/options.cli -cxx_tun := $(cxx) -cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o) $(cli_tun:.cli=.o)) -cxx_od := $(cxx_obj:.o=.o.d) - -odb_mssql.l := $(out_base)/odb-mssql.l -odb_mssql.l.cpp-options := $(out_base)/odb-mssql.l.cpp-options - -default := $(out_base)/ -dist := $(out_base)/.dist -clean := $(out_base)/.clean - -# Import. -# -$(call import,\ - $(scf_root)/import/cli/stub.make,\ - cli: cli,cli-rules: cli_rules) - -$(call import,\ - $(scf_root)/import/libodb/stub.make,\ - l: odb.l,cpp-options: odb.l.cpp-options) - -$(call import,\ - $(scf_root)/import/libodbc/stub.make,\ - l: odbc.l,\ - cpp-options: odbc.l.cpp-options) - -# Build. -# -$(odb_mssql.l): $(cxx_obj) $(odb.l) $(odbc.l) -$(odb_mssql.l.cpp-options): value := -I$(out_root) -I$(src_root) -$(odb_mssql.l.cpp-options): $(odb.l.cpp-options) $(odbc.l.cpp-options) - -$(cxx_obj) $(cxx_od): $(odb_mssql.l.cpp-options) $(out_base)/details/config.h - -genf := $(cli_tun:.cli=.hxx) $(cli_tun:.cli=.ixx) $(cli_tun:.cli=.cxx) -gen := $(addprefix $(out_base)/,$(genf)) - -# Don't try to depend on the installed executable. -# -ifneq ($(cli),cli) -$(gen): $(cli) -endif - -$(gen): cli := $(cli) -$(gen): cli_options += \ ---long-usage \ ---generate-specifier \ ---generate-file-scanner \ ---cli-namespace odb::mssql::details::cli \ ---guard-prefix LIBODB_MSSQL_DETAILS - -$(out_base)/details/config.h: | $(out_base)/details/. - @echo '/* file : odb/mssql/details/config.h' >$@ - @echo ' * note : automatically generated' >>$@ - @echo ' */' >>$@ - @echo '' >>$@ - @echo '#ifndef ODB_MSSQL_DETAILS_CONFIG_H' >>$@ - @echo '#define ODB_MSSQL_DETAILS_CONFIG_H' >>$@ - @echo '' >>$@ - @echo '#endif /* ODB_MSSQL_DETAILS_CONFIG_H */' >>$@ - -$(call include-dep,$(cxx_od),$(cxx_obj),$(gen) $(out_base)/details/config.h) - -# Convenience alias for default target. -# -$(out_base)/: $(odb_mssql.l) - -# Dist. -# -$(dist): sources_dist := $(cxx) -$(dist): export sources := $(sources_dist) $(cli_tun:.cli=.cxx) -$(dist): headers_dist = $(subst $(src_base)/,,$(shell find $(src_base) \ --name '*.hxx' -o -name '*.ixx' -o -name '*.txx')) -$(dist): gen_headers := $(cli_tun:.cli=.hxx) $(cli_tun:.cli=.ixx) -$(dist): export headers = $(sort $(headers_dist) $(gen_headers)) -$(dist): gen_dist := $(gen) -$(dist): data_dist := $(cli_tun) details/config.h.in details/config-vc.h -$(dist): export extra_dist := $(data_dist) \ -libodb-mssql-vc8.vcproj libodb-mssql-vc9.vcproj \ -libodb-mssql-vc10.vcxproj libodb-mssql-vc10.vcxproj.filters \ -libodb-mssql-vc11.vcxproj libodb-mssql-vc11.vcxproj.filters \ -libodb-mssql-vc12.vcxproj libodb-mssql-vc12.vcxproj.filters -$(dist): export interface_version = $(shell sed -e \ -'s/^\([0-9]*\.[0-9]*\).*/\1/' $(src_root)/version.txt) - -$(dist): $(gen) - $(call dist-data,$(sources_dist) $(headers_dist) $(data_dist)) - $(call dist-data,$(gen_dist),$(dist_prefix)/odb/mssql/details) - $(call meta-vc8proj,$(src_base)/libodb-mssql-vc8.vcproj) - $(call meta-vc9proj,$(src_base)/libodb-mssql-vc9.vcproj) - $(call meta-vc10proj,$(src_base)/libodb-mssql-vc10.vcxproj) - $(call meta-vc11proj,$(src_base)/libodb-mssql-vc11.vcxproj) - $(call meta-vc12proj,$(src_base)/libodb-mssql-vc12.vcxproj) - $(call meta-automake) - -# Clean. -# -$(clean): $(odb_mssql.l).o.clean \ - $(odb_mssql.l.cpp-options).clean \ - $(addsuffix .cxx.clean,$(cxx_obj)) \ - $(addsuffix .cxx.clean,$(cxx_od)) \ - $(addprefix $(out_base)/,$(cli_tun:.cli=.cxx.cli.clean)) - $(call message,rm $$1,rm -f $$1,$(out_base)/details/config.h) - -# Generated .gitignore. -# -ifeq ($(out_base),$(src_base)) -$(odb_mssql.l): | $(out_base)/.gitignore - -$(out_base)/.gitignore: files := details/config.h $(genf) -$(clean): $(out_base)/.gitignore.clean - -$(call include,$(bld_root)/git/gitignore.make) -endif - -# How to. -# -$(call include,$(bld_root)/dist.make) -$(call include,$(bld_root)/meta/vc8proj.make) -$(call include,$(bld_root)/meta/vc9proj.make) -$(call include,$(bld_root)/meta/vc10proj.make) -$(call include,$(bld_root)/meta/vc11proj.make) -$(call include,$(bld_root)/meta/vc12proj.make) -$(call include,$(bld_root)/meta/automake.make) - -$(call include,$(cli_rules)) -$(call include,$(bld_root)/cxx/o-l.make) -$(call include,$(bld_root)/cxx/cxx-o.make) -$(call include,$(bld_root)/cxx/cxx-d.make) diff --git a/odb/mssql/mssql-fwd.hxx b/odb/mssql/mssql-fwd.hxx deleted file mode 100644 index 44ac428..0000000 --- a/odb/mssql/mssql-fwd.hxx +++ /dev/null @@ -1,216 +0,0 @@ -// file : odb/mssql/mssql-fwd.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_MSSQL_FWD_HXX -#define ODB_MSSQL_MSSQL_FWD_HXX - -#include - -#include // std::size_t - -// Forward declaration for some of the types defined in sqltypes.h or -// sqlncli.h. This allows us to avoid having to include these files -// in public headers. -// -#ifdef _WIN32 - -// Keep consistent with Windows ODBC headers. -// - -typedef long SQLINTEGER; -typedef unsigned long SQLUINTEGER; - -#ifdef _WIN64 -typedef __int64 SQLLEN; -typedef unsigned __int64 SQLULEN; -#else -#ifndef SQLLEN -typedef SQLINTEGER SQLLEN; -typedef SQLUINTEGER SQLULEN; -#endif -#endif - -#else // _WIN32 - -// Keep consistent with unixODBC headers. -// - -template -struct odbc_types; - -template <> -struct odbc_types<4> -{ - typedef long integer; - typedef unsigned long uinteger; - - typedef integer len; - typedef uinteger ulen; -}; - -template <> -struct odbc_types<8> -{ - typedef int integer; - typedef unsigned int uinteger; - - typedef long len; - typedef unsigned long ulen; -}; - -typedef odbc_types::integer SQLINTEGER; -typedef odbc_types::uinteger SQLUINTEGER; - -#ifndef SQLLEN -typedef odbc_types::len SQLLEN; -typedef odbc_types::ulen SQLULEN; -#endif - -#endif // _WIN32 - -typedef short SQLSMALLINT; -typedef unsigned short SQLUSMALLINT; - -typedef SQLSMALLINT SQLRETURN; - -typedef void* SQLHANDLE; -typedef SQLHANDLE SQLHENV; -typedef SQLHANDLE SQLHDBC; -typedef SQLHANDLE SQLHSTMT; -typedef SQLHANDLE SQLHDESC; - -// If you get a redefinition error or warning for one of these macros, -// then that means you included this header (or one that includes it), -// before or . As a general rule, include or -// before any of the ODB headers. -// -#ifndef SQL_HANDLE_ENV -# define SQL_HANDLE_ENV 1 -# define SQL_HANDLE_DBC 2 -# define SQL_HANDLE_STMT 3 -# define SQL_HANDLE_DESC 4 -#endif - -#ifndef SQL_NULL_DATA -# define SQL_NULL_DATA (-1) -# define SQL_DATA_AT_EXEC (-2) -# define SQL_NO_TOTAL (-4) -#endif - -// The following types are our own equivalents of ODBC and Native Client -// ODBC driver types. They are all PODs and should be layout-compatible -// with the original types, which means they can be used interchangeably. -// -namespace odb -{ - namespace mssql - { - // UCS-2 character type (SQLWCHAR). - // -#ifdef _WIN32 - typedef wchar_t ucs2_char; -#else - typedef unsigned short ucs2_char; -#endif - - // SQL_NUMERIC_STRUCT - // -#ifndef SQL_MAX_NUMERIC_LEN -#define SQL_MAX_NUMERIC_LEN 16 -#else -# if SQL_MAX_NUMERIC_LEN != 16 -# error unexpected SQL_NUMERIC_STRUCT value -# endif -#endif - - struct decimal - { - unsigned char precision; - signed char scale; - unsigned char sign; // 1 - positive, 0 - negative - unsigned char val[SQL_MAX_NUMERIC_LEN]; - }; - - // DBMONEY - // - struct money - { - // 8-byte signed integer containing value * 10,000. - // - int high; - unsigned int low; - }; - - // DBMONEY4 - // - struct smallmoney - { - int value; // 4-byte signed integer containing value * 10,000. - }; - - // SQL_DATE_STRUCT - // - struct date - { - SQLSMALLINT year; - SQLUSMALLINT month; - SQLUSMALLINT day; - }; - - // SQL_SS_TIME2_STRUCT - // -#pragma pack(push,8) - struct time - { - SQLUSMALLINT hour; - SQLUSMALLINT minute; - SQLUSMALLINT second; - SQLUINTEGER fraction; - }; -#pragma pack(pop) - - // SQL_TIMESTAMP_STRUCT - // - struct datetime - { - SQLSMALLINT year; - SQLUSMALLINT month; - SQLUSMALLINT day; - SQLUSMALLINT hour; - SQLUSMALLINT minute; - SQLUSMALLINT second; - SQLUINTEGER fraction; - }; - - // SQL_SS_TIMESTAMPOFFSET_STRUCT - // -#pragma pack(push,8) - struct datetimeoffset - { - SQLSMALLINT year; - SQLUSMALLINT month; - SQLUSMALLINT day; - SQLUSMALLINT hour; - SQLUSMALLINT minute; - SQLUSMALLINT second; - SQLUINTEGER fraction; - SQLSMALLINT timezone_hour; - SQLSMALLINT timezone_minute; - }; -#pragma pack(pop) - - // SQLGUID - // - struct uniqueidentifier - { - unsigned int data1; - unsigned short data2; - unsigned short data3; - unsigned char data4[8]; - }; - } -} - -#include - -#endif // ODB_MSSQL_MSSQL_FWD_HXX diff --git a/odb/mssql/mssql-types.hxx b/odb/mssql/mssql-types.hxx deleted file mode 100644 index b07aeb6..0000000 --- a/odb/mssql/mssql-types.hxx +++ /dev/null @@ -1,161 +0,0 @@ -// file : odb/mssql/mssql-types.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_MSSQL_TYPES_HXX -#define ODB_MSSQL_MSSQL_TYPES_HXX - -#include - -#include // std::size_t - -#include -#include - -namespace odb -{ - namespace mssql - { - enum chunk_type - { - chunk_null, - chunk_one, - chunk_first, - chunk_next, - chunk_last, - }; - - typedef void (*param_callback_type) ( - const void* context, // User context. - std::size_t* position, // Position context. An implementation is free - // to use this to track position information. It - // is initialized to zero before the first call. - const void** buffer, // [in/out] Buffer contaning the data. On the - // the first call it contains a pointer to the - // long_callback struct (used for redirections). - std::size_t* size, // [out] Data size. - chunk_type*, // [out] The position of this chunk of data. - void* temp_buffer, // A temporary buffer that may be used by the - // implementation. - std::size_t capacity); // Capacity of the temporary buffer. - - typedef void (*result_callback_type) ( - void* context, // User context. - std::size_t* position, // Position context. An implementation is free - // to use this to track position information. It - // is initialized to zero before the first call. - void** buffer, // [in/out] Buffer to copy the data to. On the - // the first call it contains a pointer to the - // long_callback struct (used for redirections). - std::size_t* size, // [in/out] In: amount of data copied into the - // buffer after the previous call. Out: capacity - // of the buffer. - chunk_type, // The position of this chunk; chunk_first means - // this is the first call, chunk_last means there - // is no more data, chunk_null means this value is - // NULL, and chunk_one means the value is empty. - std::size_t size_left, // Contains the amount of data left or 0 if this - // information is not available. - void* temp_buffer, // A temporary buffer that may be used by the - // implementation. - std::size_t capacity); // Capacity of the temporary buffer. - - struct long_callback - { - union - { - param_callback_type param; - result_callback_type result; - } callback; - - union - { - const void* param; - void* result; - } context; - }; - - struct bind - { - // This enumeration identifies the possible buffer types that can be - // bound to a parameter or result. In most cases, these map directly - // to SQL_XXX/SQL_C_XXX codes. - // - enum buffer_type - { - bit, // Buffer is a 1-byte integer. - tinyint, // Buffer is a 1-byte integer. - smallint, // Buffer is a 2-byte integer. - int_, // Buffer is a 4-byte integer. - bigint, // Buffer is an 8-byte integer. - - decimal, // Buffer is a decimal struct (SQL_NUMERIC_STRUCT). - - smallmoney, // Buffer is a smallmoney struct (DBMONEY4). - money, // Buffer is a money struct (DBMONEY). - - float4, // Buffer is a float. - float8, // Buffer is a double. - - string, // Buffer is a char array. - long_string, // Buffer is a long_callback. - - nstring, // Buffer is a ucs2_char array. - long_nstring, // Buffer is a long_callback. - - binary, // Buffer is a byte array. - long_binary, // Buffer is a long_callback. - - date, // Buffer is a date struct (SQL_DATE_STRUCT). - time, // Buffer is a time struct (SQL_SS_TIME2_STRUCT). - datetime, // Buffer is a datetime struct - // (SQL_TIMESTAMP_STRUCT). - datetimeoffset, // Buffer is a datetimeoffset - // (SQL_SS_TIMESTAMPOFFSET_STRUCT). - - uniqueidentifier, // Buffer is a uniqueidentifier struct (SQLGUID). - rowversion, // Buffer is an 8-byte array. - - last // Used as an end of list marker. - }; - - buffer_type type; // The buffer type. - void* buffer; // The buffer. For long data this is a long_callback. - SQLLEN* size_ind; // Pointer to the size/inidicator variable. Size is - // ignored except for variable-size, [small]money, and - // rowversion types. Sepcial indicator values are - // SQL_NULL_DATA (value is NULL) and SQL_DATA_AT_EXEC - // (should be set for the long_* data types). - SQLLEN capacity; // Buffer capacity. Only used for variable-size - // types as well as to pass column/size precisions - // as follows: For string/binary parameters this - // value (minus one character for strings) is used - // as maximum column size. For decimal parameters - // it contains precision (p) and scale (s) encoded - // as (p * 100 + s). For float4 and float8 it - // contains precision. For time, datetime, and - // datatimeoffset it contains fractional seconds - // (scale). In case of datetime, the special - // value 8 indicates the SMALLDATETIME type - // which has no seconds. - }; - - // An instance of this structure specifies the function to invoke and - // the context to pass when the object/view image is about to be - // modified. This mechanism is used by the query machinery to save the - // image between result iteration and dereferencing if something gets - // executed between these two operations that would overwrite the - // image. - // - struct change_callback - { - change_callback (): callback (0), context (0) {}; - - void (*callback) (void*); - void* context; - }; - } -} - -#include - -#endif // ODB_MSSQL_MSSQL_TYPES_HXX diff --git a/odb/mssql/mssql.hxx b/odb/mssql/mssql.hxx deleted file mode 100644 index b0d2355..0000000 --- a/odb/mssql/mssql.hxx +++ /dev/null @@ -1,69 +0,0 @@ -// file : odb/mssql/mssql.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_MSSQL_HXX -#define ODB_MSSQL_MSSQL_HXX - -#include - -// This file should always be included before mssql-fwd.hxx. -// -#ifdef ODB_MSSQL_MSSQL_FWD_HXX -# error odb/mssql/mssql-fwd.hxx included before odb/mssql/mssql.hxx -#endif - -#ifdef _WIN32 -# include -#endif - -#include // Standard ODBC. - -//#define _SQLNCLI_ODBC_ -//#include // SQL Server Native Client driver specifics. - -// Instead of having a dependency on (which, BTW, is not -// currently available for the Linux version of the Native Client), -// we are going to provide the few definitions that we need ourselves. -// -#ifndef SQL_SS_LENGTH_UNLIMITED -# define SQL_SS_LENGTH_UNLIMITED 0 -#endif - -#ifndef SQL_COPT_SS_BASE -# define SQL_COPT_SS_BASE 1200 -#endif - -#ifndef SQL_COPT_SS_MARS_ENABLED -# define SQL_COPT_SS_MARS_ENABLED (SQL_COPT_SS_BASE + 24) -#endif - -#ifndef SQL_MARS_ENABLED_NO -# define SQL_MARS_ENABLED_NO 0L -# define SQL_MARS_ENABLED_YES 1L -#endif - -#ifndef SQL_COPT_SS_TXN_ISOLATION -# define SQL_COPT_SS_TXN_ISOLATION (SQL_COPT_SS_BASE + 27) -#endif - -#ifndef SQL_TXN_SS_SNAPSHOT -# define SQL_TXN_SS_SNAPSHOT 0x00000020L -#endif - -#ifndef SQL_SS_TIME2 -# define SQL_SS_TIME2 (-154) -# define SQL_SS_TIMESTAMPOFFSET (-155) -#endif - -// unixODBC doesn't define SQL_PARAM_DATA_AVAILABLE even though it -// claims ODBC version 3.80. -// -#if ODBCVER >= 0x0380 -# ifndef SQL_PARAM_DATA_AVAILABLE -# define SQL_PARAM_DATA_AVAILABLE 101 -# endif -#endif - -#include - -#endif // ODB_MSSQL_MSSQL_HXX diff --git a/odb/mssql/no-id-object-result.hxx b/odb/mssql/no-id-object-result.hxx deleted file mode 100644 index ad674bc..0000000 --- a/odb/mssql/no-id-object-result.hxx +++ /dev/null @@ -1,85 +0,0 @@ -// file : odb/mssql/no-id-object-result.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_NO_ID_OBJECT_RESULT_HXX -#define ODB_MSSQL_NO_ID_OBJECT_RESULT_HXX - -#include - -#include // std::size_t - -#include -#include - -#include - -#include -#include // query_base -#include -#include - -namespace odb -{ - namespace mssql - { - template - class no_id_object_result_impl: public odb::no_id_object_result_impl - { - public: - typedef odb::no_id_object_result_impl base_type; - - typedef typename base_type::object_type object_type; - typedef typename base_type::pointer_type pointer_type; - - typedef object_traits_impl object_traits; - typedef typename base_type::pointer_traits pointer_traits; - - typedef typename object_traits::statements_type statements_type; - - virtual - ~no_id_object_result_impl (); - - no_id_object_result_impl (const query_base&, - details::shared_ptr, - statements_type&, - const schema_version_migration*); - - virtual void - load (object_type&); - - virtual void - next (); - - virtual void - cache (); - - virtual std::size_t - size (); - - virtual void - invalidate (); - - using base_type::current; - - private: - typedef mssql::change_callback change_callback_type; - - static void - change_callback (void* context); - - private: - details::shared_ptr statement_; - statements_type& statements_; - object_traits_calls tc_; - bool can_load_; - bool use_copy_; - typename object_traits::image_type* image_copy_; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_NO_ID_OBJECT_RESULT_HXX diff --git a/odb/mssql/no-id-object-result.txx b/odb/mssql/no-id-object-result.txx deleted file mode 100644 index 06b7d15..0000000 --- a/odb/mssql/no-id-object-result.txx +++ /dev/null @@ -1,154 +0,0 @@ -// file : odb/mssql/no-id-object-result.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include -#include // result_not_cached - -#include // long_data_reload -#include - -namespace odb -{ - namespace mssql - { - template - no_id_object_result_impl:: - ~no_id_object_result_impl () - { - invalidate (); - } - - template - void no_id_object_result_impl:: - invalidate () - { - change_callback_type& cc (statements_.image ().change_callback_); - - if (cc.context == this) - { - cc.callback = 0; - cc.context = 0; - } - - delete image_copy_; - image_copy_ = 0; - - if (!this->end_) - { - statement_->free_result (); - this->end_ = true; - } - - statement_.reset (); - } - - template - no_id_object_result_impl:: - no_id_object_result_impl (const query_base&, - details::shared_ptr statement, - statements_type& statements, - const schema_version_migration* svm) - : base_type (statements.connection ()), - statement_ (statement), - statements_ (statements), - tc_ (svm), - use_copy_ (false), - image_copy_ (0) - { - } - - template - void no_id_object_result_impl:: - load (object_type& obj) - { - if (!can_load_) - throw long_data_reload (); - - object_traits::callback (this->db_, obj, callback_event::pre_load); - - tc_.init (obj, - use_copy_ ? *image_copy_ : statements_.image (), - &this->db_); - - // If we are using a copy, make sure the callback information for - // long data also comes from the copy. - // - can_load_ = !statement_->stream_result ( - use_copy_ ? &statements_.image () : 0, - use_copy_ ? image_copy_ : 0); - - object_traits::callback (this->db_, obj, callback_event::post_load); - } - - template - void no_id_object_result_impl:: - next () - { - can_load_ = true; - this->current (pointer_type ()); - - typename object_traits::image_type& im (statements_.image ()); - change_callback_type& cc (im.change_callback_); - - if (cc.context == this) - { - cc.callback = 0; - cc.context = 0; - } - - use_copy_ = false; - - if (im.version != statements_.select_image_version ()) - { - binding& b (statements_.select_image_binding ()); - tc_.bind (b.bind, im, statement_select); - statements_.select_image_version (im.version); - b.version++; - } - - if (statement_->fetch () == select_statement::no_data) - { - statement_->free_result (); - this->end_ = true; - } - else - { - cc.callback = &change_callback; - cc.context = this; - } - } - - template - void no_id_object_result_impl:: - cache () - { - } - - template - std::size_t no_id_object_result_impl:: - size () - { - throw result_not_cached (); - } - - template - void no_id_object_result_impl:: - change_callback (void* c) - { - no_id_object_result_impl* r ( - static_cast*> (c)); - - typename object_traits::image_type im (r->statements_.image ()); - - if (r->image_copy_ == 0) - r->image_copy_ = new typename object_traits::image_type (im); - else - *r->image_copy_ = im; - - im.change_callback_.callback = 0; - im.change_callback_.context = 0; - - r->use_copy_ = true; - } - } -} diff --git a/odb/mssql/no-id-object-statements.hxx b/odb/mssql/no-id-object-statements.hxx deleted file mode 100644 index 8d49355..0000000 --- a/odb/mssql/no-id-object-statements.hxx +++ /dev/null @@ -1,137 +0,0 @@ -// file : odb/mssql/no-id-object-statements.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_NO_ID_OBJECT_STATEMENTS_HXX -#define ODB_MSSQL_NO_ID_OBJECT_STATEMENTS_HXX - -#include - -#include // std::size_t - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -namespace odb -{ - namespace mssql - { - // - // Implementation for objects without object id. - // - - template - class no_id_object_statements: public statements_base - { - public: - typedef T object_type; - typedef object_traits_impl object_traits; - typedef typename object_traits::pointer_type pointer_type; - typedef typename object_traits::image_type image_type; - - typedef mssql::insert_statement insert_statement_type; - - public: - no_id_object_statements (connection_type&); - - virtual - ~no_id_object_statements (); - - // Object image. - // - image_type& - image (std::size_t i = 0) - { - return image_[i]; - } - - // Insert binding. - // - std::size_t - insert_image_version () const { return insert_image_version_;} - - void - insert_image_version (std::size_t v) {insert_image_version_ = v;} - - binding& - insert_image_binding () {return insert_image_binding_;} - - // Select binding (needed for query support). - // - std::size_t - select_image_version () const { return select_image_version_;} - - void - select_image_version (std::size_t v) {select_image_version_ = v;} - - binding& - select_image_binding () {return select_image_binding_;} - - // Statements. - // - insert_statement_type& - persist_statement () - { - if (persist_ == 0) - persist_.reset ( - new (details::shared) insert_statement_type ( - conn_, - object_traits::persist_statement, - object_traits::versioned, // Process if versioned. - insert_image_binding_, - false, - false, - 0, - false)); - - return *persist_; - } - - public: - // select = total - // insert = total - inverse; inverse == 0 for object without id - // - static const std::size_t insert_column_count = - object_traits::column_count; - - static const std::size_t select_column_count = - object_traits::column_count; - - private: - no_id_object_statements (const no_id_object_statements&); - no_id_object_statements& operator= (const no_id_object_statements&); - - private: - image_type image_[object_traits::batch]; - SQLUSMALLINT status_[object_traits::batch]; - - // Select binding. - // - std::size_t select_image_version_; - binding select_image_binding_; - bind select_image_bind_[select_column_count]; - - // Insert binding. - // - std::size_t insert_image_version_; - binding insert_image_binding_; - bind insert_image_bind_[insert_column_count]; - - details::shared_ptr persist_; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_NO_ID_OBJECT_STATEMENTS_HXX diff --git a/odb/mssql/no-id-object-statements.txx b/odb/mssql/no-id-object-statements.txx deleted file mode 100644 index 30cc438..0000000 --- a/odb/mssql/no-id-object-statements.txx +++ /dev/null @@ -1,39 +0,0 @@ -// file : odb/mssql/no-id-object-statements.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include // std::memset - -namespace odb -{ - namespace mssql - { - template - no_id_object_statements:: - ~no_id_object_statements () - { - } - - template - no_id_object_statements:: - no_id_object_statements (connection_type& conn) - : statements_base (conn), - select_image_binding_ (select_image_bind_, select_column_count), - insert_image_binding_ (insert_image_bind_, - insert_column_count, - object_traits::batch, - sizeof (image_type), - status_) - { - image_[0].version = 0; // Only version in the first element used. - select_image_version_ = 0; - insert_image_version_ = 0; - - // SELECT statements only use the first element (no batches). - // - select_image_binding_.change_callback = image_[0].change_callback (); - - std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); - std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); - } - } -} diff --git a/odb/mssql/polymorphic-object-result.hxx b/odb/mssql/polymorphic-object-result.hxx deleted file mode 100644 index 5ee9642..0000000 --- a/odb/mssql/polymorphic-object-result.hxx +++ /dev/null @@ -1,99 +0,0 @@ -// file : odb/mssql/polymorphic-object-result.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_POLYMORPHIC_OBJECT_RESULT_HXX -#define ODB_MSSQL_POLYMORPHIC_OBJECT_RESULT_HXX - -#include - -#include // std::size_t - -#include -#include - -#include - -#include -#include // query_base -#include -#include - -namespace odb -{ - namespace mssql - { - template - class polymorphic_object_result_impl: - public odb::polymorphic_object_result_impl - { - public: - typedef odb::polymorphic_object_result_impl base_type; - - typedef typename base_type::id_type id_type; - typedef typename base_type::object_type object_type; - typedef typename base_type::pointer_type pointer_type; - - typedef object_traits_impl object_traits; - typedef typename base_type::pointer_traits pointer_traits; - - typedef typename base_type::root_type root_type; - typedef typename base_type::discriminator_type discriminator_type; - - typedef object_traits_impl root_traits; - - typedef typename object_traits::image_type image_type; - typedef typename object_traits::statements_type statements_type; - - virtual - ~polymorphic_object_result_impl (); - - polymorphic_object_result_impl (const query_base&, - details::shared_ptr, - statements_type&, - const schema_version_migration*); - - virtual void - load (object_type*, bool fetch); - - virtual id_type - load_id (); - - virtual discriminator_type - load_discriminator (); - - virtual void - next (); - - virtual void - cache (); - - virtual std::size_t - size (); - - virtual void - invalidate (); - - using base_type::current; - - private: - typedef mssql::change_callback change_callback_type; - - static void - change_callback (void* context); - - private: - details::shared_ptr statement_; - statements_type& statements_; - object_traits_calls tc_; - bool can_load_; - bool use_copy_; - image_type* image_copy_; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_POLYMORPHIC_OBJECT_RESULT_HXX diff --git a/odb/mssql/polymorphic-object-result.txx b/odb/mssql/polymorphic-object-result.txx deleted file mode 100644 index 159010f..0000000 --- a/odb/mssql/polymorphic-object-result.txx +++ /dev/null @@ -1,325 +0,0 @@ -// file : odb/mssql/polymorphic-object-result.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -#include -#include // result_not_cached - -#include // long_data_reload -#include - -namespace odb -{ - namespace mssql - { - template - polymorphic_object_result_impl:: - ~polymorphic_object_result_impl () - { - invalidate (); - } - - template - void polymorphic_object_result_impl:: - invalidate () - { - change_callback_type& cc ( - statements_.root_statements ().image ().change_callback_); - - if (cc.context == this) - { - cc.context = 0; - cc.callback = 0; - } - - if (image_copy_ != 0) - { - object_traits::free_image (image_copy_); - image_copy_ = 0; - } - - if (!this->end_) - { - statement_->free_result (); - this->end_ = true; - } - - statement_.reset (); - } - - template - polymorphic_object_result_impl:: - polymorphic_object_result_impl (const query_base&, - details::shared_ptr st, - statements_type& sts, - const schema_version_migration* svm) - : base_type (sts.connection ()), - statement_ (st), - statements_ (sts), - tc_ (svm), - use_copy_ (false), - image_copy_ (0) - { - } - - template - void polymorphic_object_result_impl:: - load (object_type* pobj, bool) - { - if (!can_load_) - throw long_data_reload (); - - typename statements_type::root_statements_type& rsts ( - statements_.root_statements ()); - - // This is a top-level call so the statements cannot be locked. - // - assert (!rsts.locked ()); - typename statements_type::auto_lock l (rsts); - - image_type& i (use_copy_ ? *image_copy_ : statements_.image ()); - typename root_traits::image_type& ri ( - use_copy_ ? object_traits::root_image (i) : rsts.image ()); - - id_type id (root_traits::id (ri)); - - // Determine this object's dynamic type. - // - typedef typename root_traits::info_type info_type; - discriminator_type d (root_traits::discriminator (ri)); - - // Use the polymorphic_info() helper to get concrete_info if - // object_type is concrete and NULL if it is abstract. - // - const info_type* spi (polymorphic_info (object_traits::info)); - const info_type& pi ( - spi != 0 && spi->discriminator == d - ? *spi - : root_traits::map->find (d)); - - typedef typename root_traits::pointer_type root_pointer_type; - typedef typename root_traits::pointer_traits root_pointer_traits; - - typename object_traits::pointer_cache_traits::insert_guard ig; - - if (pobj == 0) - { - // Need to create a new instance of the dynamic type. - // - root_pointer_type rp (pi.create ()); - pointer_type p ( - root_pointer_traits::template static_pointer_cast (rp)); - - // Insert it as a root pointer (for non-unique pointers, rp should - // still be valid and for unique pointers this is a no-op). - // - ig.reset ( - object_traits::pointer_cache_traits::insert (this->db_, id, rp)); - - pobj = &pointer_traits::get_ref (p); - current (p); - } - else - { - // We are loading into an existing instance. If the static and - // dynamic types differ, then make sure the instance is at least - // of the dynamic type. - // - if (&pi != &object_traits::info) - { - const info_type& dpi (root_traits::map->find (typeid (*pobj))); - - if (&dpi != &pi && dpi.derived (pi)) - throw object_not_persistent (); // @@ type_mismatch ? - } - } - - callback_event ce (callback_event::pre_load); - pi.dispatch (info_type::call_callback, this->db_, pobj, &ce); - - tc_.init (*pobj, i, &this->db_); - - // If we are using a copy, make sure the callback information for - // long data also comes from the copy. - // - can_load_ = !statement_->stream_result ( - use_copy_ ? &statements_.image () : 0, - use_copy_ ? image_copy_ : 0); - - // Initialize the id image and binding and load the rest of the object - // (containers, dynamic part, etc). - // - typename object_traits::id_image_type& idi (statements_.id_image ()); - root_traits::init (idi, id); - - binding& idb (statements_.id_image_binding ()); - if (idi.version != statements_.id_image_version () || idb.version == 0) - { - object_traits::bind (idb.bind, idi); - statements_.id_image_version (idi.version); - idb.version++; - } - - tc_.load_ (statements_, *pobj, false); - - // Load the dynamic part of the object unless static and dynamic - // types are the same. - // - if (&pi != &object_traits::info) - { - std::size_t d (object_traits::depth); - pi.dispatch (info_type::call_load, this->db_, pobj, &d); - }; - - rsts.load_delayed (tc_.version ()); - l.unlock (); - - ce = callback_event::post_load; - pi.dispatch (info_type::call_callback, this->db_, pobj, &ce); - object_traits::pointer_cache_traits::load (ig.position ()); - ig.release (); - } - - template - typename polymorphic_object_result_impl::id_type - polymorphic_object_result_impl:: - load_id () - { - typename root_traits::image_type& i ( - use_copy_ - ? object_traits::root_image (*image_copy_) - : statements_.root_statements ().image ()); - - return root_traits::id (i); - } - - template - typename polymorphic_object_result_impl::discriminator_type - polymorphic_object_result_impl:: - load_discriminator () - { - typename root_traits::image_type& i ( - use_copy_ - ? object_traits::root_image (*image_copy_) - : statements_.root_statements ().image ()); - - return root_traits::discriminator (i); - } - - template - struct polymorphic_image_rebind - { - // Derived type version. - // - typedef object_traits_impl traits; - - static void - rebind (typename traits::statements_type& sts, - const schema_version_migration* svm) - { - typename traits::image_type& im (sts.image ()); - - if (traits::check_version (sts.select_image_versions (), im)) - { - binding& b (sts.select_image_binding (traits::depth)); - object_traits_calls tc (svm); - tc.bind (b.bind, 0, 0, im, statement_select); - traits::update_version ( - sts.select_image_versions (), im, sts.select_image_bindings ()); - } - } - }; - - template - struct polymorphic_image_rebind - { - // Root type version. - // - typedef object_traits_impl traits; - - static void - rebind (typename traits::statements_type& sts, - const schema_version_migration* svm) - { - typename traits::image_type& im (sts.image ()); - - if (im.version != sts.select_image_version ()) - { - binding& b (sts.select_image_binding ()); - object_traits_calls tc (svm); - tc.bind (b.bind, im, statement_select); - sts.select_image_version (im.version); - b.version++; - } - } - }; - - template - void polymorphic_object_result_impl:: - next () - { - can_load_ = true; - this->current (pointer_type ()); - - change_callback_type& cc ( - statements_.root_statements ().image ().change_callback_); - - if (cc.context == this) - { - cc.callback = 0; - cc.context = 0; - } - - use_copy_ = false; - polymorphic_image_rebind::rebind ( - statements_, tc_.version ()); - - if (statement_->fetch () == select_statement::no_data) - { - statement_->free_result (); - this->end_ = true; - } - else - { - cc.callback = &change_callback; - cc.context = this; - } - } - - template - void polymorphic_object_result_impl:: - cache () - { - } - - template - std::size_t polymorphic_object_result_impl:: - size () - { - throw result_not_cached (); - } - - template - void polymorphic_object_result_impl:: - change_callback (void* c) - { - polymorphic_object_result_impl* r ( - static_cast*> (c)); - image_type& im (r->statements_.image ()); - - if (r->image_copy_ == 0) - r->image_copy_ = object_traits::clone_image (im); - else - object_traits::copy_image (*r->image_copy_, im); - - typename root_traits::image_type& rim ( - r->statements_.root_statements ().image ()); - - rim.change_callback_.callback = 0; - rim.change_callback_.context = 0; - - r->use_copy_ = true; - } - } -} diff --git a/odb/mssql/polymorphic-object-statements.hxx b/odb/mssql/polymorphic-object-statements.hxx deleted file mode 100644 index c115502..0000000 --- a/odb/mssql/polymorphic-object-statements.hxx +++ /dev/null @@ -1,469 +0,0 @@ -// file : odb/mssql/polymorphic-object-statements.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX -#define ODB_MSSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX - -#include - -#include // std::size_t - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace odb -{ - namespace mssql - { - // - // Implementation for polymorphic objects. - // - - template - class polymorphic_root_object_statements: public object_statements - { - public: - typedef typename object_statements::connection_type connection_type; - typedef typename object_statements::object_traits object_traits; - typedef typename object_statements::id_image_type id_image_type; - - typedef - typename object_traits::discriminator_image_type - discriminator_image_type; - - typedef - typename object_statements::select_statement_type - select_statement_type; - - public: - // Interface compatibility with derived_object_statements. - // - typedef polymorphic_root_object_statements root_statements_type; - - root_statements_type& - root_statements () - { - return *this; - } - - public: - // Discriminator binding. - // - discriminator_image_type& - discriminator_image () {return discriminator_image_;} - - std::size_t - discriminator_image_version () const - {return discriminator_image_version_;} - - void - discriminator_image_version (std::size_t v) - {discriminator_image_version_ = v;} - - binding& - discriminator_image_binding () {return discriminator_image_binding_;} - - // Id binding for discriminator retrieval. - // - id_image_type& - discriminator_id_image () {return discriminator_id_image_;} - - std::size_t - discriminator_id_image_version () const - {return discriminator_id_image_version_;} - - void - discriminator_id_image_version (std::size_t v) - {discriminator_id_image_version_ = v;} - - binding& - discriminator_id_image_binding () - {return discriminator_id_image_binding_;} - - // - // - select_statement_type& - find_discriminator_statement () - { - if (find_discriminator_ == 0) - find_discriminator_.reset ( - new (details::shared) select_statement_type ( - this->conn_, - object_traits::find_discriminator_statement, - false, // Doesn't need to be processed. - false, // Don't optimize. - discriminator_id_image_binding_, - discriminator_image_binding_, - false)); - - return *find_discriminator_; - } - - public: - polymorphic_root_object_statements (connection_type&); - - virtual - ~polymorphic_root_object_statements (); - - // Static "override" (statements type). - // - void - load_delayed (const schema_version_migration* svm) - { - assert (this->locked ()); - - if (!this->delayed_.empty ()) - this->template load_delayed_ ( - svm); - } - - public: - static const std::size_t id_column_count = - object_statements::id_column_count; - - static const std::size_t discriminator_column_count = - object_traits::discriminator_column_count; - - static const std::size_t managed_optimistic_column_count = - object_traits::managed_optimistic_column_count; - - private: - // Discriminator image. - // - discriminator_image_type discriminator_image_; - std::size_t discriminator_image_version_; - binding discriminator_image_binding_; - bind discriminator_image_bind_[discriminator_column_count + - managed_optimistic_column_count]; - - // Id image for discriminator retrieval (only used as a parameter). - // - id_image_type discriminator_id_image_; - std::size_t discriminator_id_image_version_; - binding discriminator_id_image_binding_; - bind discriminator_id_image_bind_[id_column_count]; - - details::shared_ptr find_discriminator_; - }; - - template - class polymorphic_derived_object_statements: public statements_base - { - public: - typedef T object_type; - typedef object_traits_impl object_traits; - typedef typename object_traits::id_type id_type; - typedef typename object_traits::pointer_type pointer_type; - typedef typename object_traits::id_image_type id_image_type; - typedef typename object_traits::image_type image_type; - - typedef typename object_traits::root_type root_type; - typedef - polymorphic_root_object_statements - root_statements_type; - - typedef typename object_traits::base_type base_type; - typedef - typename object_traits::base_traits::statements_type - base_statements_type; - - typedef - typename object_traits::extra_statement_cache_type - extra_statement_cache_type; - - typedef mssql::insert_statement insert_statement_type; - typedef mssql::select_statement select_statement_type; - typedef mssql::update_statement update_statement_type; - typedef mssql::delete_statement delete_statement_type; - - typedef typename root_statements_type::auto_lock auto_lock; - - public: - polymorphic_derived_object_statements (connection_type&); - - virtual - ~polymorphic_derived_object_statements (); - - public: - // Delayed loading. - // - static void - delayed_loader (odb::database&, - const id_type&, - root_type&, - const schema_version_migration*); - - public: - // Root and immediate base statements. - // - root_statements_type& - root_statements () - { - return root_statements_; - } - - base_statements_type& - base_statements () - { - return base_statements_; - } - - public: - // Object image. - // - image_type& - image () - { - return image_; - } - - // Insert binding. - // - std::size_t - insert_image_version () const { return insert_image_version_;} - - void - insert_image_version (std::size_t v) {insert_image_version_ = v;} - - std::size_t - insert_id_binding_version () const { return insert_id_binding_version_;} - - void - insert_id_binding_version (std::size_t v) {insert_id_binding_version_ = v;} - - binding& - insert_image_binding () {return insert_image_binding_;} - - // Update binding. - // - std::size_t - update_image_version () const { return update_image_version_;} - - void - update_image_version (std::size_t v) {update_image_version_ = v;} - - std::size_t - update_id_binding_version () const { return update_id_binding_version_;} - - void - update_id_binding_version (std::size_t v) {update_id_binding_version_ = v;} - - binding& - update_image_binding () {return update_image_binding_;} - - // Select binding. - // - std::size_t* - select_image_versions () { return select_image_versions_;} - - binding* - select_image_bindings () {return select_image_bindings_;} - - binding& - select_image_binding (std::size_t d) - { - return select_image_bindings_[object_traits::depth - d]; - } - - // Object id binding (comes from the root statements). - // - id_image_type& - id_image () {return root_statements_.id_image ();} - - std::size_t - id_image_version () const {return root_statements_.id_image_version ();} - - void - id_image_version (std::size_t v) {root_statements_.id_image_version (v);} - - binding& - id_image_binding () {return root_statements_.id_image_binding ();} - - binding& - optimistic_id_image_binding () { - return root_statements_.optimistic_id_image_binding ();} - - // Statements. - // - insert_statement_type& - persist_statement () - { - // Auto id and version are in the root. - // - if (persist_ == 0) - persist_.reset ( - new (details::shared) insert_statement_type ( - conn_, - object_traits::persist_statement, - object_traits::versioned, // Process if versioned. - insert_image_binding_, - false, - false, - 0)); - - return *persist_; - } - - select_statement_type& - find_statement (std::size_t d) - { - std::size_t i (object_traits::depth - d); - details::shared_ptr& p (find_[i]); - - if (p == 0) - p.reset ( - new (details::shared) select_statement_type ( - conn_, - object_traits::find_statements[i], - object_traits::versioned, // Process if versioned. - false, // Don't optimize. - root_statements_.id_image_binding (), - select_image_bindings_[i], - false)); - - return *p; - } - - update_statement_type& - update_statement () - { - if (update_ == 0) - update_.reset ( - new (details::shared) update_statement_type ( - conn_, - object_traits::update_statement, - object_traits::versioned, // Process if versioned. - update_image_binding_, - 0, - false)); - - return *update_; - } - - delete_statement_type& - erase_statement () - { - if (erase_ == 0) - erase_.reset ( - new (details::shared) delete_statement_type ( - conn_, - object_traits::erase_statement, - root_statements_.id_image_binding (), - false)); - - return *erase_; - } - - // Extra (container, section) statement cache. - // - extra_statement_cache_type& - extra_statement_cache () - { - return extra_statement_cache_.get ( - conn_, - image_, - id_image (), - id_image_binding (), - &id_image_binding ()); // Note, not id+version. - } - - public: - // select = total - id - separate_load + base::select - // insert = total - inverse - // update = total - inverse - id - readonly - separate_update - // - static const std::size_t id_column_count = - object_traits::id_column_count; - - static const std::size_t select_column_count = - object_traits::column_count - - id_column_count - - object_traits::separate_load_column_count + - base_statements_type::select_column_count; - - static const std::size_t insert_column_count = - object_traits::column_count - - object_traits::inverse_column_count; - - static const std::size_t update_column_count = insert_column_count - - object_traits::id_column_count - - object_traits::readonly_column_count - - object_traits::separate_update_column_count; - - private: - polymorphic_derived_object_statements ( - const polymorphic_derived_object_statements&); - - polymorphic_derived_object_statements& - operator= (const polymorphic_derived_object_statements&); - - private: - root_statements_type& root_statements_; - base_statements_type& base_statements_; - - extra_statement_cache_ptr extra_statement_cache_; - - image_type image_; - - // Select binding. Here we are have an array of statements/bindings - // one for each depth. In other words, if we have classes root, base, - // and derived, then we have the following array of statements: - // - // [0] d + b + r - // [1] d + b - // [2] d - // - // Also, because we have a chain of images bound to these statements, - // we have an array of versions, one entry for each base plus one for - // our own image. - // - // A poly-abstract class only needs the first statement and in this - // case we have only one entry in the the bindings and statements - // arrays (but not versions; we still have a chain of images). - // - std::size_t select_image_versions_[object_traits::depth]; - binding select_image_bindings_[ - object_traits::abstract ? 1 : object_traits::depth]; - bind select_image_bind_[select_column_count]; - - // Insert binding. The id binding is copied from the hierarchy root. - // - std::size_t insert_image_version_; - std::size_t insert_id_binding_version_; - binding insert_image_binding_; - bind insert_image_bind_[insert_column_count]; - - // Update binding. The id suffix binding is copied from the hierarchy - // root. - // - std::size_t update_image_version_; - std::size_t update_id_binding_version_; - binding update_image_binding_; - bind update_image_bind_[update_column_count + id_column_count]; - - details::shared_ptr persist_; - details::shared_ptr find_[ - object_traits::abstract ? 1 : object_traits::depth]; - details::shared_ptr update_; - details::shared_ptr erase_; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX diff --git a/odb/mssql/polymorphic-object-statements.txx b/odb/mssql/polymorphic-object-statements.txx deleted file mode 100644 index 0ba437a..0000000 --- a/odb/mssql/polymorphic-object-statements.txx +++ /dev/null @@ -1,140 +0,0 @@ -// file : odb/mssql/polymorphic-object-statements.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include // std::memset - -#include -#include - -#include -#include -#include -#include - -namespace odb -{ - namespace mssql - { - // - // polymorphic_root_object_statements - // - - template - polymorphic_root_object_statements:: - ~polymorphic_root_object_statements () - { - } - - template - polymorphic_root_object_statements:: - polymorphic_root_object_statements (connection_type& conn) - : object_statements (conn), - discriminator_image_binding_ (discriminator_image_bind_, - discriminator_column_count + - managed_optimistic_column_count), - discriminator_id_image_binding_ (discriminator_id_image_bind_, - id_column_count) - { - discriminator_image_.version = 0; - discriminator_id_image_.version = 0; - - discriminator_image_version_ = 0; - discriminator_id_image_version_ = 0; - - std::memset ( - discriminator_image_bind_, 0, sizeof (discriminator_image_bind_)); - std::memset ( - discriminator_id_image_bind_, 0, sizeof (discriminator_id_image_bind_)); - } - - // - // polymorphic_derived_object_statements - // - - template - polymorphic_derived_object_statements:: - ~polymorphic_derived_object_statements () - { - } - - template - polymorphic_derived_object_statements:: - polymorphic_derived_object_statements (connection_type& conn) - : statements_base (conn), - root_statements_ (conn.statement_cache ().find_object ()), - base_statements_ (conn.statement_cache ().find_object ()), - insert_image_binding_ (insert_image_bind_, insert_column_count), - update_image_binding_ (update_image_bind_, - update_column_count + id_column_count) - { - image_.base = &base_statements_.image (); - image_.version = 0; - - for (std::size_t i (0); i < object_traits::depth; ++i) - select_image_versions_[i] = 0; - - for (std::size_t i (0); - i < (object_traits::abstract ? 1 : object_traits::depth); - ++i) - { - select_image_bindings_[i].bind = select_image_bind_; - select_image_bindings_[i].count = object_traits::find_column_counts[i]; - select_image_bindings_[i].change_callback = 0; - } - - // Statements other than the first one (which goes all the way to - // the root) can never override the image because they are used to - // load up the dynamic part of the object only after the static - // part has been loaded (and triggered the callback if necessary). - // - select_image_bindings_[0].change_callback = - root_statements_.image ().change_callback (); - - insert_image_version_ = 0; - insert_id_binding_version_ = 0; - update_image_version_ = 0; - update_id_binding_version_ = 0; - - std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); - std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); - std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); - } - - template - void polymorphic_derived_object_statements:: - delayed_loader (odb::database& db, - const id_type& id, - root_type& robj, - const schema_version_migration* svm) - { - connection_type& conn (transaction::current ().connection (db)); - polymorphic_derived_object_statements& sts ( - conn.statement_cache ().find_object ()); - root_statements_type& rsts (sts.root_statements ()); - - object_type& obj (static_cast (robj)); - - // The same code as in object_statements::load_delayed_(). - // - object_traits_calls tc (svm); - - if (!tc.find_ (sts, &id)) - throw object_not_persistent (); - - auto_result ar (*sts.find_[0]); - - object_traits::callback (db, obj, callback_event::pre_load); - tc.init (obj, sts.image (), &db); - sts.find_[0]->stream_result (); - ar.free (); - tc.load_ (sts, obj, false); // Load containers, etc. - - rsts.load_delayed (svm); - - { - typename root_statements_type::auto_unlock u (rsts); - object_traits::callback (db, obj, callback_event::post_load); - } - } - } -} diff --git a/odb/mssql/prepared-query.cxx b/odb/mssql/prepared-query.cxx deleted file mode 100644 index ae0389d..0000000 --- a/odb/mssql/prepared-query.cxx +++ /dev/null @@ -1,15 +0,0 @@ -// file : odb/mssql/prepared-query.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -namespace odb -{ - namespace mssql - { - prepared_query_impl:: - ~prepared_query_impl () - { - } - } -} diff --git a/odb/mssql/prepared-query.hxx b/odb/mssql/prepared-query.hxx deleted file mode 100644 index 730f7ec..0000000 --- a/odb/mssql/prepared-query.hxx +++ /dev/null @@ -1,34 +0,0 @@ -// file : odb/mssql/prepared-query.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_PREPARED_QUERY_HXX -#define ODB_MSSQL_PREPARED_QUERY_HXX - -#include - -#include - -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - struct LIBODB_MSSQL_EXPORT prepared_query_impl: odb::prepared_query_impl - { - virtual - ~prepared_query_impl (); - - prepared_query_impl (odb::connection& c): odb::prepared_query_impl (c) {} - - mssql::query_base query; - }; - } -} - -#include - -#endif // ODB_MSSQL_PREPARED_QUERY_HXX diff --git a/odb/mssql/query-const-expr.cxx b/odb/mssql/query-const-expr.cxx deleted file mode 100644 index 4e28fad..0000000 --- a/odb/mssql/query-const-expr.cxx +++ /dev/null @@ -1,14 +0,0 @@ -// file : odb/mssql/query-const-expr.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -namespace odb -{ - namespace mssql - { - // Sun CC cannot handle this in query.cxx. - // - const query_base query_base::true_expr (true); - } -} diff --git a/odb/mssql/query-dynamic.cxx b/odb/mssql/query-dynamic.cxx deleted file mode 100644 index fb49b2b..0000000 --- a/odb/mssql/query-dynamic.cxx +++ /dev/null @@ -1,157 +0,0 @@ -// file : odb/mssql/query-dynamic.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include // std::size_t - -#include - -using namespace std; - -namespace odb -{ - namespace mssql - { - static const char* logic_operators[] = {") AND (", ") OR ("}; - static const char* comp_operators[] = {"=", "!=", "<", ">", "<=", ">="}; - - static void - translate (query_base& q, const odb::query_base& s, size_t p) - { - typedef odb::query_base::clause_part part; - - const part& x (s.clause ()[p]); - - switch (x.kind) - { - case part::kind_column: - { - const query_column_base* c ( - static_cast ( - x.native_info[id_mssql].column)); - - q.append (c->table (), c->column ()); - break; - } - case part::kind_param_val: - case part::kind_param_ref: - { - const query_column_base& qc ( - *static_cast ( - x.native_info[id_mssql].column)); - - query_param_factory f ( - reinterpret_cast ( - x.native_info[id_mssql].param_factory)); - - const odb::query_param* p ( - reinterpret_cast (x.data)); - - q.append (f (p->value, qc, x.kind == part::kind_param_ref), - qc.conversion ()); - break; - } - case part::kind_native: - { - q.append (s.strings ()[x.data]); - break; - } - case part::kind_true: - case part::kind_false: - { - q.append (x.kind == part::kind_true); - break; - } - case part::op_add: - { - translate (q, s, x.data); - translate (q, s, p - 1); - break; - } - case part::op_and: - case part::op_or: - { - q += "("; - translate (q, s, x.data); - q += logic_operators[x.kind - part::op_and]; - translate (q, s, p - 1); - q += ")"; - break; - } - case part::op_not: - { - q += "NOT ("; - translate (q, s, p - 1); - q += ")"; - break; - } - case part::op_null: - case part::op_not_null: - { - translate (q, s, p - 1); - q += (x.kind == part::op_null ? "IS NULL" : "IS NOT NULL"); - break; - } - case part::op_in: - { - if (x.data != 0) - { - size_t b (p - x.data); - - translate (q, s, b - 1); // column - q += "IN ("; - - for (size_t i (b); i != p; ++i) - { - if (i != b) - q += ","; - - translate (q, s, i); - } - - q += ")"; - } - else - q.append (false); - - break; - } - case part::op_like: - { - translate (q, s, p - 2); // column - q += "LIKE"; - translate (q, s, p - 1); // pattern - break; - } - case part::op_like_escape: - { - translate (q, s, p - 3); // column - q += "LIKE"; - translate (q, s, p - 2); // pattern - q += "ESCAPE"; - translate (q, s, p - 1); // escape - break; - } - case part::op_eq: - case part::op_ne: - case part::op_lt: - case part::op_gt: - case part::op_le: - case part::op_ge: - { - translate (q, s, x.data); - q += comp_operators[x.kind - part::op_eq]; - translate (q, s, p - 1); - break; - } - } - } - - query_base:: - query_base (const odb::query_base& q) - : binding_ (0, 0) - { - if (!q.empty ()) - translate (*this, q, q.clause ().size () - 1); - } - } -} diff --git a/odb/mssql/query-dynamic.hxx b/odb/mssql/query-dynamic.hxx deleted file mode 100644 index ceb423b..0000000 --- a/odb/mssql/query-dynamic.hxx +++ /dev/null @@ -1,32 +0,0 @@ -// file : odb/mssql/query-dynamic.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_QUERY_DYNAMIC_HXX -#define ODB_MSSQL_QUERY_DYNAMIC_HXX - -#include - -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - typedef details::shared_ptr (*query_param_factory) ( - const void* val, const query_column_base&, bool by_ref); - - template - details::shared_ptr - query_param_factory_impl (const void*, const query_column_base&, bool); - } -} - -#include -#include - -#include - -#endif // ODB_MSSQL_QUERY_DYNAMIC_HXX diff --git a/odb/mssql/query-dynamic.ixx b/odb/mssql/query-dynamic.ixx deleted file mode 100644 index 005175f..0000000 --- a/odb/mssql/query-dynamic.ixx +++ /dev/null @@ -1,30 +0,0 @@ -// file : odb/mssql/query-dynamic.ixx -// license : ODB NCUEL; see accompanying LICENSE file - -namespace odb -{ - namespace mssql - { - // - // - template - inline query_column:: - query_column (odb::query_column& qc, - const char* table, - const char* column, - const char* conv, - unsigned short prec, - unsigned short scale) - : query_column_base (table, column, conv, prec, scale) - { - native_column_info& ci (qc.native_info[id_mssql]); - ci.column = static_cast (this); - - // For some reason GCC needs this statically-typed pointer in - // order to instantiate the functions. - // - query_param_factory f (&query_param_factory_impl); - ci.param_factory = reinterpret_cast (f); - } - } -} diff --git a/odb/mssql/query-dynamic.txx b/odb/mssql/query-dynamic.txx deleted file mode 100644 index 8683c0f..0000000 --- a/odb/mssql/query-dynamic.txx +++ /dev/null @@ -1,25 +0,0 @@ -// file : odb/mssql/query-dynamic.txx -// license : ODB NCUEL; see accompanying LICENSE file - -namespace odb -{ - namespace mssql - { - template - details::shared_ptr - query_param_factory_impl (const void* val, - const query_column_base& qc, - bool by_ref) - { - const T& v (*static_cast (val)); - - unsigned short p (qc.prec ()); - unsigned short s (qc.scale ()); - - return details::shared_ptr ( - by_ref - ? new (details::shared) query_param_impl (ref_bind (v, p, s)) - : new (details::shared) query_param_impl (val_bind (v, p, s))); - } - } -} diff --git a/odb/mssql/query.cxx b/odb/mssql/query.cxx deleted file mode 100644 index 6dd87e7..0000000 --- a/odb/mssql/query.cxx +++ /dev/null @@ -1,406 +0,0 @@ -// file : odb/mssql/query.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include // std::size_t -#include // std::memset, std::memcpy - -#include - -using namespace std; - -namespace odb -{ - namespace mssql - { - // query_param - // - query_param:: - ~query_param () - { - } - - // query_base - // - query_base:: - query_base (const query_base& q) - : clause_ (q.clause_), - parameters_ (q.parameters_), - bind_ (q.bind_), - binding_ (0, 0) - { - // Here and below we want to maintain up to date binding info so - // that the call to parameters_binding() below is an immutable - // operation, provided the query does not have any by-reference - // parameters. This way a by-value-only query can be shared - // between multiple threads without the need for synchronization. - // - if (size_t n = bind_.size ()) - { - binding_.bind = &bind_[0]; - binding_.count = n; - binding_.version++; - } - } - - query_base& query_base:: - operator= (const query_base& q) - { - if (this != &q) - { - clause_ = q.clause_; - parameters_ = q.parameters_; - bind_ = q.bind_; - - size_t n (bind_.size ()); - binding_.bind = n != 0 ? &bind_[0] : 0; - binding_.count = n; - binding_.version++; - } - - return *this; - } - - query_base& query_base:: - operator+= (const query_base& q) - { - clause_.insert (clause_.end (), q.clause_.begin (), q.clause_.end ()); - - size_t n (bind_.size ()); - - parameters_.insert ( - parameters_.end (), q.parameters_.begin (), q.parameters_.end ()); - - bind_.insert ( - bind_.end (), q.bind_.begin (), q.bind_.end ()); - - if (n != bind_.size ()) - { - binding_.bind = &bind_[0]; - binding_.count = bind_.size (); - binding_.version++; - } - - return *this; - } - - void query_base:: - append (const string& q) - { - if (!clause_.empty () && - clause_.back ().kind == clause_part::kind_native) - { - string& s (clause_.back ().part); - - char first (!q.empty () ? q[0] : ' '); - char last (!s.empty () ? s[s.size () - 1] : ' '); - - // We don't want extra spaces after '(' as well as before ',' - // and ')'. - // - if (last != ' ' && last != '\n' && last != '(' && - first != ' ' && first != '\n' && first != ',' && first != ')') - s += ' '; - - s += q; - } - else - clause_.push_back (clause_part (clause_part::kind_native, q)); - } - - void query_base:: - append (const char* table, const char* column) - { - string s (table); - s += '.'; - s += column; - - clause_.push_back (clause_part (clause_part::kind_column, s)); - } - - void query_base:: - append (details::shared_ptr p, const char* conv) - { - clause_.push_back (clause_part (clause_part::kind_param)); - - if (conv != 0) - clause_.back ().part = conv; - - parameters_.push_back (p); - bind_.push_back (bind ()); - binding_.bind = &bind_[0]; - binding_.count = bind_.size (); - binding_.version++; - - bind* b (&bind_.back ()); - memset (b, 0, sizeof (bind)); - p->bind (b); - } - - void query_base:: - init_parameters () const - { - bool inc_ver (false); - - for (size_t i (0); i < parameters_.size (); ++i) - { - query_param& p (*parameters_[i]); - - if (p.reference ()) - { - if (p.init ()) - { - p.bind (&bind_[i]); - inc_ver = true; - } - } - } - - if (inc_ver) - binding_.version++; - } - - static bool - check_prefix (const string& s) - { - string::size_type n; - - // It is easier to compare to upper and lower-case versions - // rather than getting involved with the portable case- - // insensitive string comparison mess. - // - if (s.compare (0, (n = 5), "WHERE") == 0 || - s.compare (0, (n = 5), "where") == 0 || - s.compare (0, (n = 6), "SELECT") == 0 || - s.compare (0, (n = 6), "select") == 0 || - s.compare (0, (n = 8), "ORDER BY") == 0 || - s.compare (0, (n = 8), "order by") == 0 || - s.compare (0, (n = 8), "GROUP BY") == 0 || - s.compare (0, (n = 8), "group by") == 0 || - s.compare (0, (n = 6), "HAVING") == 0 || - s.compare (0, (n = 6), "having") == 0 || - s.compare (0, (n = 4), "EXEC") == 0 || - s.compare (0, (n = 4), "exec") == 0 || - s.compare (0, (n = 7), "EXECUTE") == 0 || - s.compare (0, (n = 7), "execute") == 0) - { - // It either has to be an exact match, or there should be - // a whitespace following the keyword. - // - if (s.size () == n || s[n] == ' ' || s[n] == '\n' || s[n] =='\t') - return true; - } - - return false; - } - - void query_base:: - optimize () - { - // Remove a single TRUE literal or one that is followe by one of - // the other clauses. This avoids useless WHERE clauses like - // - // WHERE TRUE GROUP BY foo - // - clause_type::iterator i (clause_.begin ()), e (clause_.end ()); - - if (i != e && i->kind == clause_part::kind_bool && i->bool_part) - { - clause_type::iterator j (i + 1); - - if (j == e || - (j->kind == clause_part::kind_native && check_prefix (j->part))) - clause_.erase (i); - } - } - - const char* query_base:: - clause_prefix () const - { - if (!clause_.empty ()) - { - const clause_part& p (clause_.front ()); - - if (p.kind == clause_part::kind_native && check_prefix (p.part)) - return ""; - - return "WHERE "; - } - - return ""; - } - - string query_base:: - clause () const - { - string r; - - for (clause_type::const_iterator i (clause_.begin ()), - end (clause_.end ()); - i != end; - ++i) - { - char last (!r.empty () ? r[r.size () - 1] : ' '); - - switch (i->kind) - { - case clause_part::kind_column: - { - if (last != ' ' && last != '\n' && last != '(') - r += ' '; - - r += i->part; - break; - } - case clause_part::kind_param: - { - if (last != ' ' && last != '\n' && last != '(') - r += ' '; - - // Add the conversion expression, if any. - // - string::size_type p (0); - if (!i->part.empty ()) - { - p = i->part.find ("(?)"); - r.append (i->part, 0, p); - } - - r += '?'; - - if (!i->part.empty ()) - r.append (i->part, p + 3, string::npos); - - break; - } - case clause_part::kind_native: - { - // We don't want extra spaces after '(' as well as before ',' - // and ')'. - // - const string& p (i->part); - char first (!p.empty () ? p[0] : ' '); - - if (last != ' ' && last != '\n' && last != '(' && - first != ' ' && first != '\n' && first != ',' && first != ')') - r += ' '; - - r += p; - break; - } - case clause_part::kind_bool: - { - if (last != ' ' && last != '\n' && last != '(') - r += ' '; - - // SQL Server does not have "true" TRUE and FALSE boolean - // constants (there seem to be TRUE and FALSE literals but - // they are interpreted as integers). Boolean values seem - // to only be created as the result of boolean expressions. - // - r += i->bool_part ? "1 = 1" : "1 = 0"; - break; - } - } - } - - return clause_prefix () + r; - } - - query_base - operator&& (const query_base& x, const query_base& y) - { - // Optimize cases where one or both sides are constant truth. - // - bool xt (x.const_true ()), yt (y.const_true ()); - - if (xt && yt) - return x; - - if (xt) - return y; - - if (yt) - return x; - - query_base r ("("); - r += x; - r += ") AND ("; - r += y; - r += ")"; - return r; - } - - query_base - operator|| (const query_base& x, const query_base& y) - { - query_base r ("("); - r += x; - r += ") OR ("; - r += y; - r += ")"; - return r; - } - - query_base - operator! (const query_base& x) - { - query_base r ("NOT ("); - r += x; - r += ")"; - return r; - } - - // - // long_query_param_impl - // - - void long_query_param_impl:: - copy () - { - size_ = 0; - - // The below code is the same as in statement.cxx. - // - const void* buf (&callback_); - char tmp_buf[1024]; - - size_t position (0); - for (;;) - { - size_t n; - chunk_type chunk; - - callback_.callback.param ( - callback_.context.param, - &position, - &buf, - &n, - &chunk, - tmp_buf, - sizeof (tmp_buf)); - - if (chunk != chunk_null) - { - if (buf_.capacity () < size_ + n) - buf_.capacity (size_ + n, size_); - - memcpy (buf_.data () + size_, buf, n); - size_ += n; - } - - if (chunk == chunk_one || chunk == chunk_last) - { - // Make sure the resulting buffer is not NULL (failed that, this - // parameter will be skipped by the query machinery). - // - if (size_ == 0) - buf_.capacity (1); - - break; - } - else if (chunk == chunk_null) - break; - } - } - } -} diff --git a/odb/mssql/query.hxx b/odb/mssql/query.hxx deleted file mode 100644 index 18db752..0000000 --- a/odb/mssql/query.hxx +++ /dev/null @@ -1,2711 +0,0 @@ -// file : odb/mssql/query.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_QUERY_HXX -#define ODB_MSSQL_QUERY_HXX - -#include - -#include -#include -#include // std::size_t - -#include // odb::query_column -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -namespace odb -{ - namespace mssql - { - // For precision, 0 is invalid so we can use it as a special value - // to indicate that the precision has not been specified. For scale, - // however, 0 is a valid value and for some types (e.g., TIME) if - // the scale is not specified, it defaults to something other than - // 0. As a result, for scale, the not specific special value will - // be 0xFFFF (USHORT_MAX). - // - template - struct val_bind - { - typedef const T& type; - - explicit - val_bind (type v, unsigned short p = 0, unsigned short s = 0xFFFF) - : val (v), prec (p), scale (s) {} - - type val; - - unsigned short prec; - unsigned short scale; - }; - - template - struct val_bind - { - typedef const T* type; - - explicit - val_bind (type v, unsigned short p = 0, unsigned short s = 0xFFFF) - : val (v), prec (p), scale (s) {} - - type val; - - unsigned short prec; - unsigned short scale; - }; - - template - struct ref_bind - { - typedef const T& type; - - explicit - ref_bind (type r, unsigned short p = 0, unsigned short s = 0xFFFF) - : ref (r), prec (p), scale (s) {} - - const void* - ptr () const {return &ref;} - - type ref; - - unsigned short prec; - unsigned short scale; - }; - - template - struct ref_bind - { - typedef const T* type; - - explicit - ref_bind (type r, unsigned short p = 0, unsigned short s = 0xFFFF) - : ref (r), prec (p), scale (s) {} - - // Allow implicit conversion from decayed ref_bind's. - // - ref_bind (ref_bind r): ref (r.ref), prec (r.prec), scale (r.scale) {} - ref_bind (ref_bind r) - : ref (r.ref), prec (r.prec), scale (r.scale) {} - - const void* - ptr () const {return ref;} - - type ref; - - unsigned short prec; - unsigned short scale; - }; - - template - struct val_bind_typed: val_bind - { - explicit - val_bind_typed (typename val_bind::type v, - unsigned short p = 0, - unsigned short s = 0xFFFF): val_bind (v, p, s) {} - }; - - template - struct ref_bind_typed: ref_bind - { - explicit - ref_bind_typed (typename ref_bind::type r, - unsigned short p = 0, - unsigned short s = 0xFFFF): ref_bind (r, p, s) {} - }; - - struct LIBODB_MSSQL_EXPORT query_param: details::shared_base - { - typedef mssql::bind bind_type; - - virtual - ~query_param (); - - bool - reference () const - { - return value_ != 0; - } - - virtual bool - init () = 0; - - virtual void - bind (bind_type*) = 0; - - protected: - query_param (const void* value) - : value_ (value) - { - } - - protected: - const void* value_; - }; - - // - // - template - struct query_column; - - class LIBODB_MSSQL_EXPORT query_base - { - public: - struct clause_part - { - enum kind_type - { - kind_column, - kind_param, - kind_native, - kind_bool - }; - - clause_part (kind_type k): kind (k), bool_part (false) {} - clause_part (kind_type k, const std::string& p) - : kind (k), part (p), bool_part (false) {} - clause_part (bool p): kind (kind_bool), bool_part (p) {} - - kind_type kind; - std::string part; // If kind is param, then part is conversion expr. - bool bool_part; - }; - - query_base () - : binding_ (0, 0) - { - } - - // True or false literal. - // - explicit - query_base (bool v) - : binding_ (0, 0) - { - append (v); - } - - explicit - query_base (const char* native) - : binding_ (0, 0) - { - clause_.push_back (clause_part (clause_part::kind_native, native)); - } - - explicit - query_base (const std::string& native) - : binding_ (0, 0) - { - clause_.push_back (clause_part (clause_part::kind_native, native)); - } - - query_base (const char* table, const char* column) - : binding_ (0, 0) - { - append (table, column); - } - - template - explicit - query_base (val_bind v) - : binding_ (0, 0) - { - *this += v; - } - - template - explicit - query_base (val_bind_typed v) - : binding_ (0, 0) - { - *this += v; - } - - template - explicit - query_base (ref_bind r) - : binding_ (0, 0) - { - *this += r; - } - - template - explicit - query_base (ref_bind_typed r) - : binding_ (0, 0) - { - *this += r; - } - - template - query_base (const query_column&); - - // Translate common query representation to SQL Server native. Defined - // in query-dynamic.cxx - // - query_base (const odb::query_base&); - - // Copy c-tor and assignment. - // - query_base (const query_base&); - - query_base& - operator= (const query_base&); - - public: - std::string - clause () const; - - const char* - clause_prefix () const; - - // Initialize the by-reference parameters from bound variables. - // - void - init_parameters () const; - - binding& - parameters_binding () const; - - public: - bool - empty () const - { - return clause_.empty (); - } - - static const query_base true_expr; - - bool - const_true () const - { - return clause_.size () == 1 && - clause_.front ().kind == clause_part::kind_bool && - clause_.front ().bool_part; - } - - void - optimize (); - - public: - template - static val_bind - _val (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF) - { - return val_bind (x, prec, scale); - } - - template - static val_bind_typed - _val (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF) - { - return val_bind_typed (x, prec, scale); - } - - template - static ref_bind - _ref (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF) - { - return ref_bind (x, prec, scale); - } - - template - static ref_bind_typed - _ref (const T& x, unsigned short prec = 0, unsigned short scale = 0xFFFF) - { - return ref_bind_typed (x, prec, scale); - } - - // Some compilers (notably VC++), when deducing const T& from const - // array do not strip const from the array type. As a result, in the - // above signatures we get, for example, T = const char[4] instead - // of T = char[4], which is what we want. So to "fix" such compilers, - // we will have to provide the following specializations of the above - // functions. - // - template - static val_bind - _val (const T (&x) [N], unsigned short p = 0, unsigned short s = 0xFFFF) - { - return val_bind (x, p, s); - } - - template - static val_bind_typed - _val (const T (&x) [N], unsigned short p = 0, unsigned short s = 0xFFFF) - { - return val_bind_typed (x, p, s); - } - - template - static ref_bind - _ref (const T (&x) [N], unsigned short p = 0, unsigned short s = 0xFFFF) - { - return ref_bind (x, p, s); - } - - template - static ref_bind_typed - _ref (const T (&x) [N], unsigned short p = 0, unsigned short s = 0xFFFF) - { - return ref_bind_typed (x, p, s); - } - - public: - query_base& - operator+= (const query_base&); - - query_base& - operator+= (const std::string& q) - { - append (q); - return *this; - } - - template - query_base& - operator+= (val_bind v) - { - append::db_type_id> ( - v, details::conversion::to ()); - return *this; - } - - template - query_base& - operator+= (val_bind_typed v) - { - // We are not using default type_traits so no default conversion - // either. - // - append (v, 0); - return *this; - } - - template - query_base& - operator+= (ref_bind r) - { - append::db_type_id> ( - r, details::conversion::to ()); - return *this; - } - - template - query_base& - operator+= (ref_bind_typed r) - { - // We are not using default type_traits so no default conversion - // either. - // - append (r, 0); - return *this; - } - - template - query_base& - operator+= (const query_column&); - - // Implementation details. - // - public: - template - void - append (val_bind, const char* conv); - - template - void - append (ref_bind, const char* conv); - - void - append (details::shared_ptr, const char* conv); - - void - append (bool v) - { - clause_.push_back (clause_part (v)); - } - - void - append (const std::string& native); - - void - append (const char* native) // Clashes with append(bool). - { - append (std::string (native)); - } - - void - append (const char* table, const char* column); - - private: - typedef std::vector clause_type; - typedef std::vector > parameters_type; - - clause_type clause_; - parameters_type parameters_; - mutable std::vector bind_; - mutable binding binding_; - }; - - inline query_base - operator+ (const query_base& x, const query_base& y) - { - query_base r (x); - r += y; - return r; - } - - template - inline query_base - operator+ (const query_base& q, val_bind b) - { - query_base r (q); - r += b; - return r; - } - - template - inline query_base - operator+ (val_bind b, const query_base& q) - { - query_base r; - r += b; - r += q; - return r; - } - - template - inline query_base - operator+ (const query_base& q, val_bind_typed b) - { - query_base r (q); - r += b; - return r; - } - - template - inline query_base - operator+ (val_bind_typed b, const query_base& q) - { - query_base r; - r += b; - r += q; - return r; - } - - template - inline query_base - operator+ (const query_base& q, ref_bind b) - { - query_base r (q); - r += b; - return r; - } - - template - inline query_base - operator+ (ref_bind b, const query_base& q) - { - query_base r; - r += b; - r += q; - return r; - } - - template - inline query_base - operator+ (const query_base& q, ref_bind_typed b) - { - query_base r (q); - r += b; - return r; - } - - template - inline query_base - operator+ (ref_bind_typed b, const query_base& q) - { - query_base r; - r += b; - r += q; - return r; - } - - inline query_base - operator+ (const query_base& q, const std::string& s) - { - query_base r (q); - r += s; - return r; - } - - inline query_base - operator+ (const std::string& s, const query_base& q) - { - query_base r (s); - r += q; - return r; - } - - template - inline query_base - operator+ (const std::string& s, val_bind b) - { - query_base r (s); - r += b; - return r; - } - - template - inline query_base - operator+ (val_bind b, const std::string& s) - { - query_base r; - r += b; - r += s; - return r; - } - - template - inline query_base - operator+ (const std::string& s, val_bind_typed b) - { - query_base r (s); - r += b; - return r; - } - - template - inline query_base - operator+ (val_bind_typed b, const std::string& s) - { - query_base r; - r += b; - r += s; - return r; - } - - template - inline query_base - operator+ (const std::string& s, ref_bind b) - { - query_base r (s); - r += b; - return r; - } - - template - inline query_base - operator+ (ref_bind b, const std::string& s) - { - query_base r; - r += b; - r += s; - return r; - } - - template - inline query_base - operator+ (const std::string& s, ref_bind_typed b) - { - query_base r (s); - r += b; - return r; - } - - template - inline query_base - operator+ (ref_bind_typed b, const std::string& s) - { - query_base r; - r += b; - r += s; - return r; - } - - LIBODB_MSSQL_EXPORT query_base - operator&& (const query_base& x, const query_base& y); - - LIBODB_MSSQL_EXPORT query_base - operator|| (const query_base& x, const query_base& y); - - LIBODB_MSSQL_EXPORT query_base - operator! (const query_base& x); - - // query_column - // - struct LIBODB_MSSQL_EXPORT query_column_base - { - // Note that we keep shallow copies of the table, column, and conversion - // expression. The latter can be NULL. - // - query_column_base (const char* table, - const char* column, - const char* conv, - unsigned short prec, - unsigned short scale) - : table_ (table), column_ (column), conversion_ (conv), - prec_ (prec), scale_ (scale) - { - } - - const char* - table () const - { - return table_; - } - - const char* - column () const - { - return column_; - } - - // Can be NULL. - // - const char* - conversion () const - { - return conversion_; - } - - unsigned short - prec () const - { - return prec_; - } - - unsigned short - scale () const - { - return scale_; - } - - protected: - const char* table_; - const char* column_; - const char* conversion_; - - unsigned short prec_; - unsigned short scale_; - }; - - template - struct query_column: query_column_base - { - typedef typename decay_traits::type decayed_type; - - // Note that we keep shalow copies of the table, column, and conversion - // expression. The latter can be NULL. - // - query_column (const char* table, - const char* column, - const char* conv, - unsigned short prec = 0, - unsigned short scale = 0xFFFF) - : query_column_base (table, column, conv, prec, scale) {} - - // Implementation is in query-dynamic.ixx. - // - query_column (odb::query_column&, - const char* table, - const char* column, - const char* conv, - unsigned short prec = 0, - unsigned short scale = 0xFFFF); - - // is_null, is_not_null - // - public: - query_base - is_null () const - { - query_base q (table_, column_); - q += "IS NULL"; - return q; - } - - query_base - is_not_null () const - { - query_base q (table_, column_); - q += "IS NOT NULL"; - return q; - } - - // in - // - public: - query_base - in (decayed_type, decayed_type) const; - - query_base - in (decayed_type, decayed_type, decayed_type) const; - - query_base - in (decayed_type, decayed_type, decayed_type, decayed_type) const; - - query_base - in (decayed_type, decayed_type, decayed_type, decayed_type, - decayed_type) const; - - template - query_base - in_range (I begin, I end) const; - - // like - // - public: - query_base - like (decayed_type pattern) const - { - return like (val_bind (pattern)); - } - - query_base - like (val_bind pattern) const; - - template - query_base - like (val_bind pattern) const - { - return like (val_bind (decayed_type (pattern.val))); - } - - query_base - like (ref_bind pattern) const; - - query_base - like (decayed_type pattern, decayed_type escape) const - { - return like (val_bind (pattern), escape); - } - - query_base - like (val_bind pattern, decayed_type escape) const; - - template - query_base - like (val_bind pattern, decayed_type escape) const - { - return like (val_bind (decayed_type (pattern.val)), escape); - } - - query_base - like (ref_bind pattern, decayed_type escape) const; - - // = - // - public: - query_base - equal (decayed_type v) const - { - return equal (val_bind (v)); - } - - query_base - equal (val_bind v) const - { - v.prec = prec_; - v.scale = scale_; - - query_base q (table_, column_); - q += "="; - q.append (v, conversion_); - return q; - } - - template - query_base - equal (val_bind v) const - { - return equal (val_bind (decayed_type (v.val)));; - } - - query_base - equal (ref_bind r) const - { - r.prec = prec_; - r.scale = scale_; - - query_base q (table_, column_); - q += "="; - q.append (r, conversion_); - return q; - } - - friend query_base - operator== (const query_column& c, decayed_type v) - { - return c.equal (v); - } - - friend query_base - operator== (decayed_type v, const query_column& c) - { - return c.equal (v); - } - - friend query_base - operator== (const query_column& c, val_bind v) - { - return c.equal (v); - } - - friend query_base - operator== (val_bind v, const query_column& c) - { - return c.equal (v); - } - - template - friend query_base - operator== (const query_column& c, val_bind v) - { - return c.equal (v); - } - - template - friend query_base - operator== (val_bind v, const query_column& c) - { - return c.equal (v); - } - - friend query_base - operator== (const query_column& c, ref_bind r) - { - return c.equal (r); - } - - friend query_base - operator== (ref_bind r, const query_column& c) - { - return c.equal (r); - } - - // != - // - public: - query_base - unequal (decayed_type v) const - { - return unequal (val_bind (v)); - } - - query_base - unequal (val_bind v) const - { - v.prec = prec_; - v.scale = scale_; - - query_base q (table_, column_); - q += "!="; - q.append (v, conversion_); - return q; - } - - template - query_base - unequal (val_bind v) const - { - return unequal (val_bind (decayed_type (v.val))); - } - - query_base - unequal (ref_bind r) const - { - r.prec = prec_; - r.scale = scale_; - - query_base q (table_, column_); - q += "!="; - q.append (r, conversion_); - return q; - } - - friend query_base - operator!= (const query_column& c, decayed_type v) - { - return c.unequal (v); - } - - friend query_base - operator!= (decayed_type v, const query_column& c) - { - return c.unequal (v); - } - - friend query_base - operator!= (const query_column& c, val_bind v) - { - return c.unequal (v); - } - - friend query_base - operator!= (val_bind v, const query_column& c) - { - return c.unequal (v); - } - - template - friend query_base - operator!= (const query_column& c, val_bind v) - { - return c.unequal (v); - } - - template - friend query_base - operator!= (val_bind v, const query_column& c) - { - return c.unequal (v); - } - - friend query_base - operator!= (const query_column& c, ref_bind r) - { - return c.unequal (r); - } - - friend query_base - operator!= (ref_bind r, const query_column& c) - { - return c.unequal (r); - } - - // < - // - public: - query_base - less (decayed_type v) const - { - return less (val_bind (v)); - } - - query_base - less (val_bind v) const - { - v.prec = prec_; - v.scale = scale_; - - query_base q (table_, column_); - q += "<"; - q.append (v, conversion_); - return q; - } - - template - query_base - less (val_bind v) const - { - return less (val_bind (decayed_type (v.val))); - } - - query_base - less (ref_bind r) const - { - r.prec = prec_; - r.scale = scale_; - - query_base q (table_, column_); - q += "<"; - q.append (r, conversion_); - return q; - } - - friend query_base - operator< (const query_column& c, decayed_type v) - { - return c.less (v); - } - - friend query_base - operator< (decayed_type v, const query_column& c) - { - return c.greater (v); - } - - friend query_base - operator< (const query_column& c, val_bind v) - { - return c.less (v); - } - - friend query_base - operator< (val_bind v, const query_column& c) - { - return c.greater (v); - } - - template - friend query_base - operator< (const query_column& c, val_bind v) - { - return c.less (v); - } - - template - friend query_base - operator< (val_bind v, const query_column& c) - { - return c.greater (v); - } - - friend query_base - operator< (const query_column& c, ref_bind r) - { - return c.less (r); - } - - friend query_base - operator< (ref_bind r, const query_column& c) - { - return c.greater (r); - } - - // > - // - public: - query_base - greater (decayed_type v) const - { - return greater (val_bind (v)); - } - - query_base - greater (val_bind v) const - { - v.prec = prec_; - v.scale = scale_; - - query_base q (table_, column_); - q += ">"; - q.append (v, conversion_); - return q; - } - - template - query_base - greater (val_bind v) const - { - return greater (val_bind (decayed_type (v.val))); - } - - query_base - greater (ref_bind r) const - { - r.prec = prec_; - r.scale = scale_; - - query_base q (table_, column_); - q += ">"; - q.append (r, conversion_); - return q; - } - - friend query_base - operator> (const query_column& c, decayed_type v) - { - return c.greater (v); - } - - friend query_base - operator> (decayed_type v, const query_column& c) - { - return c.less (v); - } - - friend query_base - operator> (const query_column& c, val_bind v) - { - return c.greater (v); - } - - friend query_base - operator> (val_bind v, const query_column& c) - { - return c.less (v); - } - - template - friend query_base - operator> (const query_column& c, val_bind v) - { - return c.greater (v); - } - - template - friend query_base - operator> (val_bind v, const query_column& c) - { - return c.less (v); - } - - friend query_base - operator> (const query_column& c, ref_bind r) - { - return c.greater (r); - } - - friend query_base - operator> (ref_bind r, const query_column& c) - { - return c.less (r); - } - - // <= - // - public: - query_base - less_equal (decayed_type v) const - { - return less_equal (val_bind (v)); - } - - query_base - less_equal (val_bind v) const - { - v.prec = prec_; - v.scale = scale_; - - query_base q (table_, column_); - q += "<="; - q.append (v, conversion_); - return q; - } - - template - query_base - less_equal (val_bind v) const - { - return less_equal (val_bind (decayed_type (v.val))); - } - - query_base - less_equal (ref_bind r) const - { - r.prec = prec_; - r.scale = scale_; - - query_base q (table_, column_); - q += "<="; - q.append (r, conversion_); - return q; - } - - friend query_base - operator<= (const query_column& c, decayed_type v) - { - return c.less_equal (v); - } - - friend query_base - operator<= (decayed_type v, const query_column& c) - { - return c.greater_equal (v); - } - - friend query_base - operator<= (const query_column& c, val_bind v) - { - return c.less_equal (v); - } - - friend query_base - operator<= (val_bind v, const query_column& c) - { - return c.greater_equal (v); - } - - template - friend query_base - operator<= (const query_column& c, val_bind v) - { - return c.less_equal (v); - } - - template - friend query_base - operator<= (val_bind v, const query_column& c) - { - return c.greater_equal (v); - } - - friend query_base - operator<= (const query_column& c, ref_bind r) - { - return c.less_equal (r); - } - - friend query_base - operator<= (ref_bind r, const query_column& c) - { - return c.greater_equal (r); - } - - // >= - // - public: - query_base - greater_equal (decayed_type v) const - { - return greater_equal (val_bind (v)); - } - - query_base - greater_equal (val_bind v) const - { - v.prec = prec_; - v.scale = scale_; - - query_base q (table_, column_); - q += ">="; - q.append (v, conversion_); - return q; - } - - template - query_base - greater_equal (val_bind v) const - { - return greater_equal (val_bind (decayed_type (v.val))); - } - - query_base - greater_equal (ref_bind r) const - { - r.prec = prec_; - r.scale = scale_; - - query_base q (table_, column_); - q += ">="; - q.append (r, conversion_); - return q; - } - - friend query_base - operator>= (const query_column& c, decayed_type v) - { - return c.greater_equal (v); - } - - friend query_base - operator>= (decayed_type v, const query_column& c) - { - return c.less_equal (v); - } - - friend query_base - operator>= (const query_column& c, val_bind v) - { - return c.greater_equal (v); - } - - friend query_base - operator>= (val_bind v, const query_column& c) - { - return c.less_equal (v); - } - - template - friend query_base - operator>= (const query_column& c, val_bind v) - { - return c.greater_equal (v); - } - - template - friend query_base - operator>= (val_bind v, const query_column& c) - { - return c.less_equal (v); - } - - friend query_base - operator>= (const query_column& c, ref_bind r) - { - return c.greater_equal (r); - } - - friend query_base - operator>= (ref_bind r, const query_column& c) - { - return c.less_equal (r); - } - - // Column comparison. - // - public: - template - query_base - operator== (const query_column& c) const - { - // We can compare columns only if we can compare their C++ types. - // - (void) (sizeof (decay_traits::instance () == - decay_traits::instance ())); - - query_base q (table_, column_); - q += "="; - q.append (c.table (), c.column ()); - return q; - } - - template - query_base - operator!= (const query_column& c) const - { - // We can compare columns only if we can compare their C++ types. - // - (void) (sizeof (decay_traits::instance () != - decay_traits::instance ())); - - query_base q (table_, column_); - q += "!="; - q.append (c.table (), c.column ()); - return q; - } - - template - query_base - operator< (const query_column& c) const - { - // We can compare columns only if we can compare their C++ types. - // - (void) (sizeof (decay_traits::instance () < - decay_traits::instance ())); - - query_base q (table_, column_); - q += "<"; - q.append (c.table (), c.column ()); - return q; - } - - template - query_base - operator> (const query_column& c) const - { - // We can compare columns only if we can compare their C++ types. - // - (void) (sizeof (decay_traits::instance () > - decay_traits::instance ())); - - query_base q (table_, column_); - q += ">"; - q.append (c.table (), c.column ()); - return q; - } - - template - query_base - operator<= (const query_column& c) const - { - // We can compare columns only if we can compare their C++ types. - // - (void) (sizeof (decay_traits::instance () <= - decay_traits::instance ())); - - query_base q (table_, column_); - q += "<="; - q.append (c.table (), c.column ()); - return q; - } - - template - query_base - operator>= (const query_column& c) const - { - // We can compare columns only if we can compare their C++ types. - // - (void) (sizeof (decay_traits::instance () >= - decay_traits::instance ())); - - query_base q (table_, column_); - q += ">="; - q.append (c.table (), c.column ()); - return q; - } - }; - - // Provide operator+() for using columns to construct native - // query fragments (e.g., ORDER BY). - // - template - inline query_base - operator+ (const query_column& c, const std::string& s) - { - query_base q (c.table (), c.column ()); - q += s; - return q; - } - - template - inline query_base - operator+ (const std::string& s, const query_column& c) - { - query_base q (s); - q.append (c.table (), c.column ()); - return q; - } - - template - inline query_base - operator+ (const query_column& c, const query_base& q) - { - query_base r (c.table (), c.column ()); - r += q; - return r; - } - - template - inline query_base - operator+ (const query_base& q, const query_column& c) - { - query_base r (q); - r.append (c.table (), c.column ()); - return r; - } - - template - inline query_base& query_base:: - operator+= (const query_column& c) - { - append (c.table (), c.column ()); - return *this; - } - - // - // - template - struct query_param_impl; - - // id_bit. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) : query_param (r.ptr ()) {} - query_param_impl (val_bind v) : query_param (0) {init (v.val);} - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::bit; - b->buffer = &image_; - b->size_ind = &size_ind_; - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 0; - } - - private: - unsigned char image_; - SQLLEN size_ind_; - }; - - // id_tinyint. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) : query_param (r.ptr ()) {} - query_param_impl (val_bind v) : query_param (0) {init (v.val);} - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::tinyint; - b->buffer = &image_; - b->size_ind = &size_ind_; - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 0; - } - - private: - unsigned char image_; - SQLLEN size_ind_; - }; - - // id_smallint. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) : query_param (r.ptr ()) {} - query_param_impl (val_bind v) : query_param (0) {init (v.val);} - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::smallint; - b->buffer = &image_; - b->size_ind = &size_ind_; - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 0; - } - - private: - short image_; - SQLLEN size_ind_; - }; - - // id_int. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) : query_param (r.ptr ()) {} - query_param_impl (val_bind v) : query_param (0) {init (v.val);} - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::int_; - b->buffer = &image_; - b->size_ind = &size_ind_; - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 0; - } - - private: - int image_; - SQLLEN size_ind_; - }; - - // id_bigint. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) : query_param (r.ptr ()) {} - query_param_impl (val_bind v) : query_param (0) {init (v.val);} - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::bigint; - b->buffer = &image_; - b->size_ind = &size_ind_; - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 0; - } - - private: - long long image_; - SQLLEN size_ind_; - }; - - // id_decimal. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), - prec_ (r.prec != 0 ? r.prec : 18), // Default is 18. - scale_ (r.scale != 0xFFFF ? r.scale : 0) // Default is 0. - { - } - - query_param_impl (val_bind v) - : query_param (0), - prec_ (v.prec != 0 ? v.prec : 18), // Default is 18. - scale_ (v.scale) - { - init (v.val); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::decimal; - b->buffer = &image_; - b->size_ind = &size_ind_; - // Encode precision (p) and scale (s) as (p * 100 + s). - // - b->capacity = static_cast (prec_ * 100 + scale_); - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 0; - } - - private: - unsigned short prec_; - unsigned short scale_; - - decimal image_; - SQLLEN size_ind_; - }; - - // id_smallmoney. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) : query_param (r.ptr ()) {} - query_param_impl (val_bind v) : query_param (0) {init (v.val);} - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::smallmoney; - b->buffer = &image_; - b->size_ind = &size_ind_; - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 4; - } - - private: - smallmoney image_; - SQLLEN size_ind_; - }; - - // id_money. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) : query_param (r.ptr ()) {} - query_param_impl (val_bind v) : query_param (0) {init (v.val);} - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::money; - b->buffer = &image_; - b->size_ind = &size_ind_; - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 8; - } - - private: - money image_; - SQLLEN size_ind_; - }; - - // id_float4. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), - prec_ (r.prec != 0 ? r.prec : 24) - { - } - - query_param_impl (val_bind v) - : query_param (0), - prec_ (v.prec != 0 ? v.prec : 24) - { - init (v.val); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::float4; - b->buffer = &image_; - b->size_ind = &size_ind_; - b->capacity = static_cast (prec_); - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 0; - } - - private: - unsigned short prec_; - float image_; - SQLLEN size_ind_; - }; - - // id_float8. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), - prec_ (r.prec != 0 ? r.prec : 53) - { - } - - query_param_impl (val_bind v) - : query_param (0), - prec_ (v.prec != 0 ? v.prec : 53) - { - init (v.val); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::float8; - b->buffer = &image_; - b->size_ind = &size_ind_; - b->capacity = static_cast (prec_); - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 0; - } - - private: - unsigned short prec_; - double image_; - SQLLEN size_ind_; - }; - - // id_string. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), - // Default to short data max (1024). - buf_ (r.prec != 0 ? r.prec : 1024) - { - } - - query_param_impl (val_bind v) - : query_param (0), - // Default to short data max (1024). - buf_ (v.prec != 0 ? v.prec : 1024) - { - init (v.val); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::string; - b->buffer = buf_.data (); - b->size_ind = &size_ind_; - // Extra byte for the null terminator (convention). - // - b->capacity = static_cast (buf_.capacity () + 1); - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - std::size_t size (0); - value_traits::set_image ( - buf_.data (), buf_.capacity (), size, is_null, v); - size_ind_ = static_cast (size); - } - - private: - details::buffer buf_; - SQLLEN size_ind_; - }; - - // id_nstring. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), - // Precision is in 2-byte chars. Default to short data max (1024). - buf_ (r.prec != 0 ? r.prec * 2 : 1024) - { - } - - query_param_impl (val_bind v) - : query_param (0), - // Precision is in 2-byte chars. Default to short data max (1024). - buf_ (v.prec != 0 ? v.prec * 2 : 1024) - { - init (v.val); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::nstring; - b->buffer = buf_.data (); - b->size_ind = &size_ind_; - // Extra two bytes for the null terminator (convention). - // - b->capacity = static_cast (buf_.capacity () + 2); - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - std::size_t size (0); - value_traits::set_image ( - reinterpret_cast (buf_.data ()), - buf_.capacity () / 2, - size, - is_null, - v); - size_ind_ = static_cast (size * 2); - } - - private: - details::buffer buf_; - SQLLEN size_ind_; - }; - - // id_binary. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), - // Default to short data max (1024). - buf_ (r.prec != 0 ? r.prec : 1024) - { - } - - query_param_impl (val_bind v) - : query_param (0), - // Default to short data max (1024). - buf_ (v.prec != 0 ? v.prec : 1024) - { - init (v.val); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::binary; - b->buffer = buf_.data (); - b->size_ind = &size_ind_; - b->capacity = static_cast (buf_.capacity ()); - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - std::size_t size (0); - value_traits::set_image ( - buf_.data (), buf_.capacity (), size, is_null, v); - size_ind_ = static_cast (size); - } - - private: - details::buffer buf_; - SQLLEN size_ind_; - }; - - // long_query_param_impl - // - // For long data we cannot assume that the by-value parameter will - // still be alive when we execute the query (and when the callback - // will be called to provide the data). So we have to make a private - // copy of the data and use that when the time comes. - // - class LIBODB_MSSQL_EXPORT long_query_param_impl - { - protected: - long_query_param_impl (): buf_ (0) {} - - void - copy (); - - protected: - details::buffer buf_; - std::size_t size_; - long_callback callback_; - }; - - // id_long_string. - // - template - struct query_param_impl: query_param, - long_query_param_impl - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), prec_ (r.prec) - { - } - - query_param_impl (val_bind v) - : query_param (0), prec_ (v.prec) - { - init (v.val); - copy (); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - // If this is a by-value parameter then we already have the - // buffer containing all the data. So instead of using the - // callback mechanism, bind the buffer directly using the - // short data approach. SQLLEN (int on 32-bit platforms) - // can represent maximum size of 2^31 bytes which happens - // to be greater than the maximum size of VARCHAR(max) or - // TEXT (both 2^31-1 bytes). - // - if (reference ()) - { - b->type = bind::long_string; - b->buffer = &this->long_query_param_impl::callback_; - b->size_ind = &size_ind_; - b->capacity = static_cast (prec_); - size_ind_ = SQL_DATA_AT_EXEC; - } - else - { - b->type = bind::string; - b->buffer = buf_.data (); - b->size_ind = &size_ind_; - // Extra byte for the null terminator (convention). - // - b->capacity = static_cast (prec_ != 0 ? prec_ + 1 : 0); - size_ind_ = static_cast (size_); - } - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image ( - long_query_param_impl::callback_.callback.param, - long_query_param_impl::callback_.context.param, - is_null, - v); - } - - private: - unsigned short prec_; - SQLLEN size_ind_; - }; - - // id_long_nstring. - // - template - struct query_param_impl: query_param, - long_query_param_impl - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), prec_ (r.prec) - { - } - - query_param_impl (val_bind v) - : query_param (0), prec_ (v.prec) - { - init (v.val); - copy (); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - // If this is a by-value parameter then we already have the - // buffer containing all the data. So instead of using the - // callback mechanism, bind the buffer directly using the - // short data approach. SQLLEN (int on 32-bit platforms) - // can represent maximum size of 2^31 bytes which happens - // to be greater than the maximum size of NVARCHAR(max) or - // NTEXT (both 2^31-1 bytes). - // - if (reference ()) - { - b->type = bind::long_nstring; - b->buffer = &this->long_query_param_impl::callback_; - b->size_ind = &size_ind_; - b->capacity = static_cast (prec_ * 2); // In bytes. - size_ind_ = SQL_DATA_AT_EXEC; - } - else - { - b->type = bind::nstring; - b->buffer = buf_.data (); - b->size_ind = &size_ind_; - // In bytes, extra character for the null terminator (convention). - // - b->capacity = static_cast (prec_ != 0 ? (prec_ + 1) * 2 : 0); - size_ind_ = static_cast (size_); - } - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image ( - long_query_param_impl::callback_.callback.param, - long_query_param_impl::callback_.context.param, - is_null, - v); - } - - private: - unsigned short prec_; - SQLLEN size_ind_; - }; - - // id_long_binary. - // - template - struct query_param_impl: query_param, - long_query_param_impl - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), prec_ (r.prec) - { - } - - query_param_impl (val_bind v) - : query_param (0), prec_ (v.prec) - { - init (v.val); - copy (); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - // If this is a by-value parameter then we already have the - // buffer containing all the data. So instead of using the - // callback mechanism, bind the buffer directly using the - // short data approach. SQLLEN (int on 32-bit platforms) - // can represent maximum size of 2^31 bytes which happens - // to be greater than the maximum size of VARBINARY(max) - // or IMAGE (both 2^31-1 bytes). - // - if (reference ()) - { - b->type = bind::long_binary; - b->buffer = &this->long_query_param_impl::callback_; - b->size_ind = &size_ind_; - size_ind_ = SQL_DATA_AT_EXEC; - } - else - { - b->type = bind::binary; - b->buffer = buf_.data (); - b->size_ind = &size_ind_; - size_ind_ = static_cast (size_); - } - - b->capacity = static_cast (prec_); - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image ( - long_query_param_impl::callback_.callback.param, - long_query_param_impl::callback_.context.param, - is_null, - v); - } - - private: - unsigned short prec_; - SQLLEN size_ind_; - }; - - // id_date. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) : query_param (r.ptr ()) {} - query_param_impl (val_bind v) : query_param (0) {init (v.val);} - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::date; - b->buffer = &image_; - b->size_ind = &size_ind_; - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 0; - } - - private: - date image_; - SQLLEN size_ind_; - }; - - // id_time. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), - scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default is 7. - { - } - - query_param_impl (val_bind v) - : query_param (0), - scale_ (v.scale != 0xFFFF ? v.scale : 7) // Default is 7. - { - init (v.val); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::time; - b->buffer = &image_; - b->size_ind = &size_ind_; - b->capacity = static_cast (scale_); - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, scale_, is_null, v); - size_ind_ = static_cast (sizeof (image_)); - } - - private: - unsigned short scale_; - time image_; - SQLLEN size_ind_; - }; - - // id_datetime. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), - scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default to datetime2/7. - { - } - - query_param_impl (val_bind v) - : query_param (0), - scale_ (v.scale != 0xFFFF ? v.scale : 7) // Default to datetime2/7. - { - init (v.val); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::datetime; - b->buffer = &image_; - b->size_ind = &size_ind_; - b->capacity = static_cast (scale_); - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, scale_, is_null, v); - size_ind_ = 0; - } - - private: - unsigned short scale_; - datetime image_; - SQLLEN size_ind_; - }; - - // id_datetimeoffset. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) - : query_param (r.ptr ()), - scale_ (r.scale != 0xFFFF ? r.scale : 7) // Default is 7. - { - } - - query_param_impl (val_bind v) - : query_param (0), - scale_ (v.scale != 0xFFFF ? v.scale : 7) // Default is 7. - { - init (v.val); - } - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::datetimeoffset; - b->buffer = &image_; - b->size_ind = &size_ind_; - b->capacity = static_cast (scale_); - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image ( - image_, scale_, is_null, v); - size_ind_ = static_cast (sizeof (image_)); - } - - private: - unsigned short scale_; - datetimeoffset image_; - SQLLEN size_ind_; - }; - - // id_uniqueidentifier. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) : query_param (r.ptr ()) {} - query_param_impl (val_bind v) : query_param (0) {init (v.val);} - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::uniqueidentifier; - b->buffer = &image_; - b->size_ind = &size_ind_; - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 0; - } - - private: - uniqueidentifier image_; - SQLLEN size_ind_; - }; - - // id_rowversion. - // - template - struct query_param_impl: query_param - { - query_param_impl (ref_bind r) : query_param (r.ptr ()) {} - query_param_impl (val_bind v) : query_param (0) {init (v.val);} - - virtual bool - init () - { - init (*static_cast (value_)); - return false; - } - - virtual void - bind (bind_type* b) - { - b->type = bind::rowversion; - b->buffer = &image_; - b->size_ind = &size_ind_; - } - - private: - void - init (typename decay_traits::type v) - { - bool is_null (false); // Can't be NULL. - value_traits::set_image (image_, is_null, v); - size_ind_ = 8; - } - - private: - unsigned char image_[8]; - SQLLEN size_ind_; - }; - } -} - -// odb::mssql::query and odb::query specialization for SQL Server. -// -namespace odb -{ - namespace mssql - { - template - class query: public query_base, - public query_selector::columns_type - { - public: - // We don't define any typedefs here since they may clash with - // column names defined by our base type. - // - - query () - { - } - - explicit - query (bool v) - : query_base (v) - { - } - - explicit - query (const char* q) - : query_base (q) - { - } - - explicit - query (const std::string& q) - : query_base (q) - { - } - - template - explicit - query (val_bind v) - : query_base (v) - { - } - - template - explicit - query (ref_bind r) - : query_base (r) - { - } - - query (const query_base& q) - : query_base (q) - { - } - - template - query (const query_column& qc) - : query_base (qc) - { - } - - query (const odb::query_base& q) - : query_base (q) - { - } - }; - - namespace core - { - using mssql::query; - } - } - - // Derive odb::query from odb::mssql::query so that it can be - // implicitly converted in mssql::database::query() calls. - // - template - class query: public mssql::query - { - public: - // We don't define any typedefs here since they may clash with - // column names defined by our base type. - // - - query () - { - } - - explicit - query (bool v) - : mssql::query (v) - { - } - - explicit - query (const char* q) - : mssql::query (q) - { - } - - explicit - query (const std::string& q) - : mssql::query (q) - { - } - - template - explicit - query (mssql::val_bind v) - : mssql::query (v) - { - } - - template - explicit - query (mssql::ref_bind r) - : mssql::query (r) - { - } - - query (const mssql::query_base& q) - : mssql::query (q) - { - } - - template - query (const mssql::query_column& qc) - : mssql::query (qc) - { - } - }; -} - -#include -#include - -#include - -#endif // ODB_MSSQL_QUERY_HXX diff --git a/odb/mssql/query.ixx b/odb/mssql/query.ixx deleted file mode 100644 index 0467667..0000000 --- a/odb/mssql/query.ixx +++ /dev/null @@ -1,34 +0,0 @@ -// file : odb/mssql/query.ixx -// license : ODB NCUEL; see accompanying LICENSE file - -namespace odb -{ - namespace mssql - { - inline binding& query_base:: - parameters_binding () const - { - return binding_; - } - - template - inline void query_base:: - append (val_bind v, const char* conv) - { - append ( - details::shared_ptr ( - new (details::shared) query_param_impl (v)), - conv); - } - - template - inline void query_base:: - append (ref_bind r, const char* conv) - { - append ( - details::shared_ptr ( - new (details::shared) query_param_impl (r)), - conv); - } - } -} diff --git a/odb/mssql/query.txx b/odb/mssql/query.txx deleted file mode 100644 index d01747c..0000000 --- a/odb/mssql/query.txx +++ /dev/null @@ -1,169 +0,0 @@ -// file : odb/mssql/query.txx -// license : ODB NCUEL; see accompanying LICENSE file - -namespace odb -{ - namespace mssql - { - // - // query_base - // - - template - query_base:: - query_base (const query_column& c) - : binding_ (0, 0) - { - // Cannot use IS TRUE here since database type can be a non- - // integral type. - // - append (c.table (), c.column ()); - append ("="); - append (val_bind (true, c.prec (), c.scale ()), - c.conversion ()); - } - - // - // query_column - // - - // in - // - template - query_base query_column:: - in (decayed_type v1, decayed_type v2) const - { - query_base q (table_, column_); - q += "IN ("; - q.append (val_bind (v1, prec_, scale_), conversion_); - q += ","; - q.append (val_bind (v2, prec_, scale_), conversion_); - q += ")"; - return q; - } - - template - query_base query_column:: - in (decayed_type v1, decayed_type v2, decayed_type v3) const - { - query_base q (table_, column_); - q += "IN ("; - q.append (val_bind (v1, prec_, scale_), conversion_); - q += ","; - q.append (val_bind (v2, prec_, scale_), conversion_); - q += ","; - q.append (val_bind (v3, prec_, scale_), conversion_); - q += ")"; - return q; - } - - template - query_base query_column:: - in (decayed_type v1, decayed_type v2, decayed_type v3, - decayed_type v4) const - { - query_base q (table_, column_); - q += "IN ("; - q.append (val_bind (v1, prec_, scale_), conversion_); - q += ","; - q.append (val_bind (v2, prec_, scale_), conversion_); - q += ","; - q.append (val_bind (v3, prec_, scale_), conversion_); - q += ","; - q.append (val_bind (v4, prec_, scale_), conversion_); - q += ")"; - return q; - } - - template - query_base query_column:: - in (decayed_type v1, decayed_type v2, decayed_type v3, decayed_type v4, - decayed_type v5) const - { - query_base q (table_, column_); - q += "IN ("; - q.append (val_bind (v1, prec_, scale_), conversion_); - q += ","; - q.append (val_bind (v2, prec_, scale_), conversion_); - q += ","; - q.append (val_bind (v3, prec_, scale_), conversion_); - q += ","; - q.append (val_bind (v4, prec_, scale_), conversion_); - q += ","; - q.append (val_bind (v5, prec_, scale_), conversion_); - q += ")"; - return q; - } - - template - template - query_base query_column:: - in_range (I begin, I end) const - { - if (begin != end) - { - query_base q (table_, column_); - q += "IN ("; - - for (I i (begin); i != end; ++i) - { - if (i != begin) - q += ","; - - q.append (val_bind (*i, prec_, scale_), conversion_); - } - - q += ")"; - return q; - } - else - return query_base (false); - } - - // like - // - template - query_base query_column:: - like (val_bind p) const - { - query_base q (table_, column_); - q += "LIKE"; - q.append (p, conversion_); - return q; - } - - template - query_base query_column:: - like (ref_bind p) const - { - query_base q (table_, column_); - q += "LIKE"; - q.append (p, conversion_); - return q; - } - - template - query_base query_column:: - like (val_bind p, decayed_type e) const - { - query_base q (table_, column_); - q += "LIKE"; - q.append (p, conversion_); - q += "ESCAPE"; - q.append (val_bind (e), conversion_); - return q; - } - - template - query_base query_column:: - like (ref_bind p, decayed_type e) const - { - query_base q (table_, column_); - q += "LIKE"; - q.append (p, conversion_); - q += "ESCAPE"; - q.append (val_bind (e), conversion_); - return q; - } - } -} diff --git a/odb/mssql/section-statements.hxx b/odb/mssql/section-statements.hxx deleted file mode 100644 index 0f3500d..0000000 --- a/odb/mssql/section-statements.hxx +++ /dev/null @@ -1,201 +0,0 @@ -// file : odb/mssql/section-statements.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_SECTION_STATEMENTS_HXX -#define ODB_MSSQL_SECTION_STATEMENTS_HXX - -#include - -#include // std::size_t - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace odb -{ - namespace mssql - { - class connection; - - // Template argument is the section traits type. - // - template - class section_statements - { - public: - typedef ST traits; - - typedef typename traits::image_type image_type; - typedef typename traits::id_image_type id_image_type; - - typedef mssql::select_statement select_statement_type; - typedef mssql::update_statement update_statement_type; - - typedef mssql::connection connection_type; - - section_statements (connection_type&, - image_type&, id_image_type&, - binding& id, binding& idv); - - connection_type& - connection () {return conn_;} - - const schema_version_migration& - version_migration (const char* name = "") const - { - if (svm_ == 0) - svm_ = &conn_.database ().schema_version_migration (name); - - return *svm_; - } - - image_type& - image () {return image_;} - - id_image_type& - id_image () {return id_image_;} - - const binding& - id_binding () {return id_binding_;} - - // Id and optimistic concurrency version (if any). - // - const binding& - idv_binding () {return idv_binding_;} - - // Select binding. - // - std::size_t - select_image_version () const { return select_image_version_;} - - void - select_image_version (std::size_t v) {select_image_version_ = v;} - - binding& - select_image_binding () {return select_image_binding_;} - - // Update binding. - // - std::size_t - update_image_version () const { return update_image_version_;} - - void - update_image_version (std::size_t v) {update_image_version_ = v;} - - std::size_t - update_id_binding_version () const { return update_id_binding_version_;} - - void - update_id_binding_version (std::size_t v) {update_id_binding_version_ = v;} - - binding& - update_image_binding () {return update_image_binding_;} - - // - // Statements. - // - - select_statement_type& - select_statement () - { - if (select_ == 0) - select_.reset ( - new (details::shared) select_statement_type ( - conn_, - traits::select_statement, - traits::versioned, // Process if versioned. - false, // Don't optimize. - id_binding_, - select_image_binding_, - false)); - - return *select_; - } - - update_statement_type& - update_statement () - { - if (update_ == 0) - update_.reset ( - new (details::shared) update_statement_type ( - conn_, - traits::update_statement, - traits::versioned, // Process if versioned. - update_image_binding_, - (traits::rowversion ? &idv_binding_ : 0), - false)); - - return *update_; - } - - public: - static const std::size_t id_column_count = traits::id_column_count; - static const std::size_t managed_optimistic_load_column_count = - traits::managed_optimistic_load_column_count; - static const std::size_t managed_optimistic_update_column_count = - traits::managed_optimistic_update_column_count; - static const std::size_t select_column_count = traits::load_column_count; - static const std::size_t update_column_count = - traits::update_column_count; - - private: - section_statements (const section_statements&); - section_statements& operator= (const section_statements&); - - protected: - connection_type& conn_; - mutable const schema_version_migration* svm_; - - // These come from object_statements. - // - image_type& image_; - id_image_type& id_image_; - binding& id_binding_; - binding& idv_binding_; - - // Select binding. - // - std::size_t select_image_version_; - - static const std::size_t select_bind_count = - select_column_count != 0 || managed_optimistic_load_column_count != 0 - ? select_column_count + managed_optimistic_load_column_count - : 1; - - binding select_image_binding_; - bind select_image_bind_[select_bind_count]; - - // Update binding. - // - std::size_t update_image_version_; - std::size_t update_id_binding_version_; - - static const std::size_t update_bind_count = - update_column_count != 0 || managed_optimistic_update_column_count != 0 - ? update_column_count + id_column_count + - managed_optimistic_update_column_count - : 1; - - binding update_image_binding_; - bind update_image_bind_[update_bind_count]; - - details::shared_ptr select_; - details::shared_ptr update_; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_SECTION_STATEMENTS_HXX diff --git a/odb/mssql/section-statements.txx b/odb/mssql/section-statements.txx deleted file mode 100644 index 7389d82..0000000 --- a/odb/mssql/section-statements.txx +++ /dev/null @@ -1,50 +0,0 @@ -// file : odb/mssql/section-statements.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include // std::memset - -namespace odb -{ - namespace mssql - { - template - section_statements:: - section_statements (connection_type& conn, - image_type& im, id_image_type& idim, - binding& id, binding& idv) - : conn_ (conn), - svm_ (0), - image_ (im), - id_image_ (idim), - id_binding_ (id), - idv_binding_ (idv), - select_image_binding_ (select_image_bind_, - select_column_count + - managed_optimistic_load_column_count), - update_image_binding_ (update_image_bind_, - update_column_count + id_column_count + - managed_optimistic_update_column_count) - { - select_image_version_ = 0; - update_image_version_ = 0; - update_id_binding_version_ = 0; - - // If we are using optimistic concurrency, then the select statement - // will override the version member in the object image. - // - if (managed_optimistic_load_column_count != 0) - { - // Getting to the root image in polymorphic case is tricky. - // - typedef object_traits_impl object_traits; - - select_image_binding_.change_callback = - root_image::get ( - image_).change_callback (); - } - - std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); - std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); - } - } -} diff --git a/odb/mssql/simple-object-result.hxx b/odb/mssql/simple-object-result.hxx deleted file mode 100644 index dcf8243..0000000 --- a/odb/mssql/simple-object-result.hxx +++ /dev/null @@ -1,89 +0,0 @@ -// file : odb/mssql/simple-object-result.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_SIMPLE_OBJECT_RESULT_HXX -#define ODB_MSSQL_SIMPLE_OBJECT_RESULT_HXX - -#include - -#include // std::size_t - -#include -#include - -#include - -#include -#include // query_base -#include -#include - -namespace odb -{ - namespace mssql - { - template - class object_result_impl: public odb::object_result_impl - { - public: - typedef odb::object_result_impl base_type; - - typedef typename base_type::id_type id_type; - typedef typename base_type::object_type object_type; - typedef typename base_type::pointer_type pointer_type; - - typedef object_traits_impl object_traits; - typedef typename base_type::pointer_traits pointer_traits; - - typedef typename object_traits::statements_type statements_type; - - virtual - ~object_result_impl (); - - object_result_impl (const query_base&, - details::shared_ptr, - statements_type&, - const schema_version_migration*); - - virtual void - load (object_type&, bool fetch); - - virtual id_type - load_id (); - - virtual void - next (); - - virtual void - cache (); - - virtual std::size_t - size (); - - virtual void - invalidate (); - - using base_type::current; - - private: - typedef mssql::change_callback change_callback_type; - - static void - change_callback (void* context); - - private: - details::shared_ptr statement_; - statements_type& statements_; - object_traits_calls tc_; - bool can_load_; - bool use_copy_; - typename object_traits::image_type* image_copy_; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_SIMPLE_OBJECT_RESULT_HXX diff --git a/odb/mssql/simple-object-result.txx b/odb/mssql/simple-object-result.txx deleted file mode 100644 index 3a0e984..0000000 --- a/odb/mssql/simple-object-result.txx +++ /dev/null @@ -1,186 +0,0 @@ -// file : odb/mssql/simple-object-result.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -#include -#include // result_not_cached - -#include // long_data_reload -#include - -namespace odb -{ - namespace mssql - { - template - object_result_impl:: - ~object_result_impl () - { - invalidate (); - } - - template - void object_result_impl:: - invalidate () - { - change_callback_type& cc (statements_.image ().change_callback_); - - if (cc.context == this) - { - cc.callback = 0; - cc.context = 0; - } - - delete image_copy_; - image_copy_ = 0; - - if (!this->end_) - { - statement_->free_result (); - this->end_ = true; - } - - statement_.reset (); - } - - template - object_result_impl:: - object_result_impl (const query_base&, - details::shared_ptr statement, - statements_type& statements, - const schema_version_migration* svm) - : base_type (statements.connection ()), - statement_ (statement), - statements_ (statements), - tc_ (svm), - use_copy_ (false), - image_copy_ (0) - { - } - - template - void object_result_impl:: - load (object_type& obj, bool) - { - if (!can_load_) - throw long_data_reload (); - - // This is a top-level call so the statements cannot be locked. - // - assert (!statements_.locked ()); - typename statements_type::auto_lock l (statements_); - - object_traits::callback (this->db_, obj, callback_event::pre_load); - - typename object_traits::image_type& i ( - use_copy_ ? *image_copy_ : statements_.image ()); - - tc_.init (obj, i, &this->db_); - - // If we are using a copy, make sure the callback information for - // long data also comes from the copy. - // - can_load_ = !statement_->stream_result ( - use_copy_ ? &statements_.image () : 0, - use_copy_ ? image_copy_ : 0); - - // Initialize the id image and binding and load the rest of the object - // (containers, etc). - // - typename object_traits::id_image_type& idi (statements_.id_image ()); - object_traits::init (idi, object_traits::id (i)); - - binding& idb (statements_.id_image_binding ()); - if (idi.version != statements_.id_image_version () || idb.version == 0) - { - object_traits::bind (idb.bind, idi); - statements_.id_image_version (idi.version); - idb.version++; - } - - tc_.load_ (statements_, obj, false); - statements_.load_delayed (tc_.version ()); - l.unlock (); - object_traits::callback (this->db_, obj, callback_event::post_load); - } - - template - typename object_result_impl::id_type - object_result_impl:: - load_id () - { - return object_traits::id ( - use_copy_ ? *image_copy_ : statements_.image ()); - } - - template - void object_result_impl:: - next () - { - can_load_ = true; - this->current (pointer_type ()); - - typename object_traits::image_type& im (statements_.image ()); - change_callback_type& cc (im.change_callback_); - - if (cc.context == this) - { - cc.callback = 0; - cc.context = 0; - } - - use_copy_ = false; - - if (im.version != statements_.select_image_version ()) - { - binding& b (statements_.select_image_binding ()); - tc_.bind (b.bind, im, statement_select); - statements_.select_image_version (im.version); - b.version++; - } - - if (statement_->fetch () == select_statement::no_data) - { - statement_->free_result (); - this->end_ = true; - } - else - { - cc.callback = &change_callback; - cc.context = this; - } - } - - template - void object_result_impl:: - cache () - { - } - - template - std::size_t object_result_impl:: - size () - { - throw result_not_cached (); - } - - template - void object_result_impl:: - change_callback (void* c) - { - object_result_impl* r (static_cast*> (c)); - typename object_traits::image_type& im (r->statements_.image ()); - - if (r->image_copy_ == 0) - r->image_copy_ = new typename object_traits::image_type (im); - else - *r->image_copy_ = im; - - im.change_callback_.callback = 0; - im.change_callback_.context = 0; - - r->use_copy_ = true; - } - } -} diff --git a/odb/mssql/simple-object-statements.cxx b/odb/mssql/simple-object-statements.cxx deleted file mode 100644 index 5d7e8b6..0000000 --- a/odb/mssql/simple-object-statements.cxx +++ /dev/null @@ -1,15 +0,0 @@ -// file : odb/mssql/simple-object-statements.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -namespace odb -{ - namespace mssql - { - object_statements_base:: - ~object_statements_base () - { - } - } -} diff --git a/odb/mssql/simple-object-statements.hxx b/odb/mssql/simple-object-statements.hxx deleted file mode 100644 index 9cece2c..0000000 --- a/odb/mssql/simple-object-statements.hxx +++ /dev/null @@ -1,606 +0,0 @@ -// file : odb/mssql/simple-object-statements.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_SIMPLE_OBJECT_STATEMENTS_HXX -#define ODB_MSSQL_SIMPLE_OBJECT_STATEMENTS_HXX - -#include - -#include -#include -#include // std::size_t - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - // The extra_statement_cache class is only defined (and used) in - // the generated source file. However, object_statements may be - // referenced from another source file in the case of a polymorphic - // hierarchy (though in this case the extra statement cache is - // not used). As a result, we cannot have a by-value member and - // instead will store a pointer and lazily allocate the cache if - // and when needed. We will also need to store a pointer to the - // deleter function which will be initialized during allocation - // (at that point we know that the cache class is defined). - // - template - struct extra_statement_cache_ptr - { - typedef I image_type; - typedef ID id_image_type; - typedef mssql::connection connection_type; - - extra_statement_cache_ptr (): p_ (0) {} - ~extra_statement_cache_ptr () - { - if (p_ != 0) - (this->*deleter_) (0, 0, 0, 0, 0); - } - - T& - get (connection_type& c, - image_type& im, id_image_type& idim, - binding& id, binding* idv) - { - if (p_ == 0) - allocate (&c, &im, &idim, &id, (idv != 0 ? idv : &id)); - - return *p_; - } - - private: - void - allocate (connection_type*, - image_type*, id_image_type*, - binding*, binding*); - - private: - T* p_; - void (extra_statement_cache_ptr::*deleter_) ( - connection_type*, image_type*, id_image_type*, binding*, binding*); - }; - - template - void extra_statement_cache_ptr:: - allocate (connection_type* c, - image_type* im, id_image_type* idim, - binding* id, binding* idv) - { - // To reduce object code size, this function acts as both allocator - // and deleter. - // - if (p_ == 0) - { - p_ = new T (*c, *im, *idim, *id, *idv); - deleter_ = &extra_statement_cache_ptr::allocate; - } - else - delete p_; - } - - // - // Implementation for objects with object id. - // - - class LIBODB_MSSQL_EXPORT object_statements_base: public statements_base - { - // Locking. - // - public: - void - lock () - { - assert (!locked_); - locked_ = true; - } - - void - unlock () - { - assert (locked_); - locked_ = false; - } - - bool - locked () const - { - return locked_; - } - - struct auto_unlock - { - // Unlocks the statement on construction and re-locks it on - // destruction. - // - auto_unlock (object_statements_base&); - ~auto_unlock (); - - private: - auto_unlock (const auto_unlock&); - auto_unlock& operator= (const auto_unlock&); - - private: - object_statements_base& s_; - }; - - public: - virtual - ~object_statements_base (); - - protected: - object_statements_base (connection_type& conn) - : statements_base (conn), locked_ (false) - { - } - - protected: - bool locked_; - }; - - template - struct optimistic_data; - - template - struct optimistic_data - { - typedef T object_type; - typedef object_traits_impl object_traits; - - optimistic_data (bind*, std::size_t skip, SQLUSMALLINT* status); - - binding* - id_image_binding () {return &id_image_binding_;} - - // The id + optimistic column binding. - // - binding id_image_binding_; - - details::shared_ptr erase_; - }; - - template - struct optimistic_data - { - optimistic_data (bind*, std::size_t, SQLUSMALLINT*) {} - - binding* - id_image_binding () {return 0;} - }; - - template - class object_statements: public object_statements_base - { - public: - typedef T object_type; - typedef object_traits_impl object_traits; - typedef typename object_traits::id_type id_type; - typedef typename object_traits::pointer_type pointer_type; - typedef typename object_traits::image_type image_type; - typedef typename object_traits::id_image_type id_image_type; - - typedef - typename object_traits::pointer_cache_traits - pointer_cache_traits; - - typedef - typename object_traits::extra_statement_cache_type - extra_statement_cache_type; - - typedef mssql::insert_statement insert_statement_type; - typedef mssql::select_statement select_statement_type; - typedef mssql::update_statement update_statement_type; - typedef mssql::delete_statement delete_statement_type; - - // Automatic lock. - // - struct auto_lock - { - // Lock the statements unless they are already locked in which - // case subsequent calls to locked() will return false. - // - auto_lock (object_statements&); - - // Unlock the statements if we are holding the lock and clear - // the delayed loads. This should only happen in case an - // exception is thrown. In normal circumstances, the user - // should call unlock() explicitly. - // - ~auto_lock (); - - // Return true if this auto_lock instance holds the lock. - // - bool - locked () const; - - // Unlock the statements. - // - void - unlock (); - - private: - auto_lock (const auto_lock&); - auto_lock& operator= (const auto_lock&); - - private: - object_statements& s_; - bool locked_; - }; - - public: - object_statements (connection_type&); - - virtual - ~object_statements (); - - // Delayed loading. - // - typedef void (*loader_function) (odb::database&, - const id_type&, - object_type&, - const schema_version_migration*); - - void - delay_load (const id_type& id, - object_type& obj, - const typename pointer_cache_traits::position_type& p, - loader_function l = 0) - { - delayed_.push_back (delayed_load (id, obj, p, l)); - } - - void - load_delayed (const schema_version_migration* svm) - { - assert (locked ()); - - if (!delayed_.empty ()) - load_delayed_ (svm); - } - - void - clear_delayed () - { - if (!delayed_.empty ()) - clear_delayed_ (); - } - - // Object image. - // - image_type& - image (std::size_t i = 0) - { - return images_[i].obj; - } - - // Insert binding. - // - std::size_t - insert_image_version () const { return insert_image_version_;} - - void - insert_image_version (std::size_t v) {insert_image_version_ = v;} - - binding& - insert_image_binding () {return insert_image_binding_;} - - // Update binding. - // - std::size_t - update_image_version () const { return update_image_version_;} - - void - update_image_version (std::size_t v) {update_image_version_ = v;} - - std::size_t - update_id_image_version () const { return update_id_image_version_;} - - void - update_id_image_version (std::size_t v) {update_id_image_version_ = v;} - - binding& - update_image_binding () {return update_image_binding_;} - - // Select binding. - // - std::size_t - select_image_version () const { return select_image_version_;} - - void - select_image_version (std::size_t v) {select_image_version_ = v;} - - binding& - select_image_binding () {return select_image_binding_;} - - // Object id image and binding. - // - id_image_type& - id_image (std::size_t i = 0) {return images_[i].id;} - - std::size_t - id_image_version () const {return id_image_version_;} - - void - id_image_version (std::size_t v) {id_image_version_ = v;} - - binding& - id_image_binding () {return id_image_binding_;} - - // Optimistic id + managed column image binding. It points to - // the same suffix as id binding and they are always updated - // at the same time. - // - binding& - optimistic_id_image_binding () {return *od_.id_image_binding ();} - - // Statements. - // - insert_statement_type& - persist_statement () - { - if (persist_ == 0) - persist_.reset ( - new (details::shared) insert_statement_type ( - conn_, - object_traits::persist_statement, - object_traits::versioned, // Process if versioned. - insert_image_binding_, - object_traits::auto_id, - object_traits::rowversion, - (object_traits::rowversion - ? &optimistic_id_image_binding () - : (object_traits::auto_id ? &id_image_binding () : 0)), - false)); - - return *persist_; - } - - select_statement_type& - find_statement () - { - if (find_ == 0) - find_.reset ( - new (details::shared) select_statement_type ( - conn_, - object_traits::find_statement, - object_traits::versioned, // Process if versioned. - false, // Don't optimize. - id_image_binding_, - select_image_binding_, - false)); - - return *find_; - } - - update_statement_type& - update_statement () - { - if (update_ == 0) - update_.reset ( - new (details::shared) update_statement_type ( - conn_, - object_traits::update_statement, - true, // Unique (0 or 1). - object_traits::versioned, // Process if versioned. - update_image_binding_, - object_traits::rowversion ? &optimistic_id_image_binding () : 0, - false)); - - return *update_; - } - - delete_statement_type& - erase_statement () - { - if (erase_ == 0) - erase_.reset ( - new (details::shared) delete_statement_type ( - conn_, - object_traits::erase_statement, - true, // Unique (0 or 1 affected rows). - id_image_binding_, - false)); - - return *erase_; - } - - delete_statement_type& - optimistic_erase_statement () - { - if (od_.erase_ == 0) - { - od_.erase_.reset ( - new (details::shared) delete_statement_type ( - conn_, - object_traits::optimistic_erase_statement, - true, // Unique (0 or 1 affected rows). - od_.id_image_binding_, - false)); - } - - return *od_.erase_; - } - - // Extra (container, section) statement cache. - // - extra_statement_cache_type& - extra_statement_cache () - { - return extra_statement_cache_.get ( - conn_, - images_[0].obj, images_[0].id, - id_image_binding_, od_.id_image_binding ()); - } - - public: - // select = total - separate_load - // insert = total - inverse - managed_optimistic - auto_id - // update = total - inverse - managed_optimistic - id - readonly - // - separate_update - // - static const std::size_t id_column_count = - object_traits::id_column_count; - - static const std::size_t managed_optimistic_column_count = - object_traits::managed_optimistic_column_count; - - static const std::size_t select_column_count = - object_traits::column_count - - object_traits::separate_load_column_count; - - static const std::size_t insert_column_count = - object_traits::column_count - - object_traits::inverse_column_count - - object_traits::managed_optimistic_column_count - - (object_traits::auto_id ? id_column_count : 0); - - static const std::size_t update_column_count = - insert_column_count - - (object_traits::auto_id ? 0 : id_column_count) - - object_traits::readonly_column_count - - object_traits::separate_update_column_count; - - private: - object_statements (const object_statements&); - object_statements& operator= (const object_statements&); - - protected: - template - void - load_delayed_ (const schema_version_migration*); - - void - clear_delayed_ (); - - protected: - template - friend class polymorphic_derived_object_statements; - - extra_statement_cache_ptr extra_statement_cache_; - - // The UPDATE statement uses both the object and id image. Keep - // them next to each other so that the same skip distance can - // be used in batch binding. - // - struct images - { - image_type obj; - id_image_type id; - }; - - images images_[object_traits::batch]; - SQLUSMALLINT status_[object_traits::batch]; - - // Select binding. - // - std::size_t select_image_version_; - binding select_image_binding_; - bind select_image_bind_[select_column_count]; - - // Insert binding. - // - std::size_t insert_image_version_; - binding insert_image_binding_; - bind insert_image_bind_[ - insert_column_count != 0 ? insert_column_count : 1]; - - // Update binding. Note that the id suffix is bound to id_image_ - // below instead of image_ which makes this binding effectively - // bound to two images. As a result, we have to track versions - // for both of them. If this object uses optimistic concurrency, - // then the binding for the managed column (version, timestamp, - // etc) comes after the id and the image for such a column is - // stored as part of the id image. - // - std::size_t update_image_version_; - std::size_t update_id_image_version_; - binding update_image_binding_; - bind update_image_bind_[update_column_count + id_column_count + - managed_optimistic_column_count]; - - // Id image binding (only used as a parameter or in OUTPUT for - // auto id and version). Uses the suffix in the update bind. - // - std::size_t id_image_version_; - binding id_image_binding_; - - // Extra data for objects with optimistic concurrency support. - // - optimistic_data od_; - - details::shared_ptr persist_; - details::shared_ptr find_; - details::shared_ptr update_; - details::shared_ptr erase_; - - // Delayed loading. - // - struct delayed_load - { - typedef typename pointer_cache_traits::position_type position_type; - - delayed_load () {} - delayed_load (const id_type& i, - object_type& o, - const position_type& p, - loader_function l) - : id (i), obj (&o), pos (p), loader (l) - { - } - - id_type id; - object_type* obj; - position_type pos; - loader_function loader; - }; - - typedef std::vector delayed_loads; - delayed_loads delayed_; - - // Delayed vectors swap guard. See the load_delayed_() function for - // details. - // - struct swap_guard - { - swap_guard (object_statements& os, delayed_loads& dl) - : os_ (os), dl_ (dl) - { - dl_.swap (os_.delayed_); - } - - ~swap_guard () - { - os_.clear_delayed (); - dl_.swap (os_.delayed_); - } - - private: - object_statements& os_; - delayed_loads& dl_; - }; - }; - } -} - -#include -#include - -#include - -#endif // ODB_MSSQL_SIMPLE_OBJECT_STATEMENTS_HXX diff --git a/odb/mssql/simple-object-statements.ixx b/odb/mssql/simple-object-statements.ixx deleted file mode 100644 index 1066850..0000000 --- a/odb/mssql/simple-object-statements.ixx +++ /dev/null @@ -1,68 +0,0 @@ -// file : odb/mssql/simple-object-statements.ixx -// license : ODB NCUEL; see accompanying LICENSE file - -namespace odb -{ - namespace mssql - { - // - // auto_unlock - // - inline object_statements_base::auto_unlock:: - auto_unlock (object_statements_base& s) - : s_ (s) - { - s_.unlock (); - } - - inline object_statements_base::auto_unlock:: - ~auto_unlock () - { - s_.lock (); - } - - // - // auto_lock - // - template - inline object_statements::auto_lock:: - auto_lock (object_statements& s) - : s_ (s) - { - if (!s_.locked ()) - { - s_.lock (); - locked_ = true; - } - else - locked_ = false; - } - - template - inline object_statements::auto_lock:: - ~auto_lock () - { - if (locked_) - { - s_.unlock (); - s_.clear_delayed (); - } - } - - template - inline bool object_statements::auto_lock:: - locked () const - { - return locked_; - } - - template - inline void object_statements::auto_lock:: - unlock () - { - assert (locked_); - s_.unlock (); - locked_ = false; - } - } -} diff --git a/odb/mssql/simple-object-statements.txx b/odb/mssql/simple-object-statements.txx deleted file mode 100644 index 06a0651..0000000 --- a/odb/mssql/simple-object-statements.txx +++ /dev/null @@ -1,173 +0,0 @@ -// file : odb/mssql/simple-object-statements.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include // std::memset - -#include -#include - -#include -#include - -namespace odb -{ - namespace mssql - { - // - // optimistic_data - // - - template - optimistic_data:: - optimistic_data (bind* b, std::size_t skip, SQLUSMALLINT* status) - : id_image_binding_ ( - b, - object_traits::id_column_count + - object_traits::managed_optimistic_column_count, - object_traits::batch, - skip, - status) - { - } - - // - // object_statements - // - - template - object_statements:: - ~object_statements () - { - } - - template - object_statements:: - object_statements (connection_type& conn) - : object_statements_base (conn), - select_image_binding_ (select_image_bind_, select_column_count), - insert_image_binding_ (insert_image_bind_, - insert_column_count, - object_traits::batch, - sizeof (images), - status_), - update_image_binding_ (update_image_bind_, - update_column_count + id_column_count + - managed_optimistic_column_count, - // No support for bulk update and ROWVERSION. - // - (object_traits::rowversion - ? 1 - : object_traits::batch), - sizeof (images), - status_), - id_image_binding_ (update_image_bind_ + update_column_count, - id_column_count, - object_traits::batch, - sizeof (images), - status_), - od_ (update_image_bind_ + update_column_count, - sizeof (images), - status_) - { - // Only versions in the first element used. - // - images_[0].obj.version = 0; - images_[0].id.version = 0; - - select_image_version_ = 0; - insert_image_version_ = 0; - update_image_version_ = 0; - update_id_image_version_ = 0; - id_image_version_ = 0; - - // SELECT statements only use the first element (no batches). - // - select_image_binding_.change_callback = - images_[0].obj.change_callback (); - - std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); - std::memset (update_image_bind_, 0, sizeof (update_image_bind_)); - std::memset (select_image_bind_, 0, sizeof (select_image_bind_)); - } - - template - template - void object_statements:: - load_delayed_ (const schema_version_migration* svm) - { - database& db (connection ().database ()); - - delayed_loads dls; - swap_guard sg (*this, dls); - - while (!dls.empty ()) - { - delayed_load l (dls.back ()); - typename pointer_cache_traits::insert_guard ig (l.pos); - dls.pop_back (); - - if (l.loader == 0) - { - object_traits_calls tc (svm); - - if (!tc.find_ (static_cast (*this), &l.id)) - throw object_not_persistent (); - - // Our find_() version delays result freeing. - // - auto_result ar (*find_); - - object_traits::callback (db, *l.obj, callback_event::pre_load); - - // Our calls to init/load below can result in additional delayed - // loads being added to the delayed_ vector. We need to process - // those before we call the post callback. - // - tc.init (*l.obj, image (), &db); - find_->stream_result (); - ar.free (); - - // Load containers, etc. - // - tc.load_ (static_cast (*this), *l.obj, false); - - if (!delayed_.empty ()) - load_delayed_ (svm); - - // Temporarily unlock the statement for the post_load call so that - // it can load objects of this type recursively. This is safe to do - // because we have completely loaded the current object. Also the - // delayed_ list is clear before the unlock and should be clear on - // re-lock (since a callback can only call public API functions - // which will make sure all the delayed loads are processed before - // returning). - // - { - auto_unlock u (*this); - object_traits::callback (db, *l.obj, callback_event::post_load); - } - } - else - l.loader (db, l.id, *l.obj, svm); - - pointer_cache_traits::load (ig.position ()); - ig.release (); - } - } - - template - void object_statements:: - clear_delayed_ () - { - // Remove the objects from the session cache. - // - for (typename delayed_loads::iterator i (delayed_.begin ()), - e (delayed_.end ()); i != e; ++i) - { - pointer_cache_traits::erase (i->pos); - } - - delayed_.clear (); - } - } -} diff --git a/odb/mssql/statement-cache.hxx b/odb/mssql/statement-cache.hxx deleted file mode 100644 index cf06b94..0000000 --- a/odb/mssql/statement-cache.hxx +++ /dev/null @@ -1,59 +0,0 @@ -// file : odb/mssql/statement-cache.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_STATEMENT_CACHE_HXX -#define ODB_MSSQL_STATEMENT_CACHE_HXX - -#include - -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - class LIBODB_MSSQL_EXPORT statement_cache - { - public: - statement_cache (connection& conn) - : conn_ (conn), - version_seq_ (conn_.database ().schema_version_sequence ()) {} - - template - typename object_traits_impl::statements_type& - find_object (); - - template - view_statements& - find_view (); - - private: - typedef std::map, - details::type_info_comparator> map; - - connection& conn_; - unsigned int version_seq_; - map map_; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_STATEMENT_CACHE_HXX diff --git a/odb/mssql/statement-cache.txx b/odb/mssql/statement-cache.txx deleted file mode 100644 index 84424e3..0000000 --- a/odb/mssql/statement-cache.txx +++ /dev/null @@ -1,60 +0,0 @@ -// file : odb/mssql/statement-cache.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -namespace odb -{ - namespace mssql - { - template - typename object_traits_impl::statements_type& - statement_cache:: - find_object () - { - typedef - typename object_traits_impl::statements_type - statements_type; - - // Clear the cache if the database version has changed. This - // makes sure we don't re-use statements that correspond to - // the old schema. - // - if (version_seq_ != conn_.database ().schema_version_sequence ()) - { - map_.clear (); - version_seq_ = conn_.database ().schema_version_sequence (); - } - - map::iterator i (map_.find (&typeid (T))); - - if (i != map_.end ()) - return static_cast (*i->second); - - details::shared_ptr p ( - new (details::shared) statements_type (conn_)); - - map_.insert (map::value_type (&typeid (T), p)); - return *p; - } - - template - view_statements& statement_cache:: - find_view () - { - // We don't cache any statements for views so no need to clear - // the cache. - - map::iterator i (map_.find (&typeid (T))); - - if (i != map_.end ()) - return static_cast&> (*i->second); - - details::shared_ptr > p ( - new (details::shared) view_statements (conn_)); - - map_.insert (map::value_type (&typeid (T), p)); - return *p; - } - } -} diff --git a/odb/mssql/statement-processing.cxx b/odb/mssql/statement-processing.cxx deleted file mode 100644 index 0c3072a..0000000 --- a/odb/mssql/statement-processing.cxx +++ /dev/null @@ -1,356 +0,0 @@ -// file : odb/mssql/statement-processing.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -#include - -#ifdef LIBODB_TRACE_STATEMENT_PROCESSING -# include -#endif - -#include - -using namespace std; - -namespace odb -{ - namespace mssql - { - typedef bind bind_type; - - void statement:: - process_select (std::string& r, - const char* s, - const bind_type* bind, - std::size_t bind_size, -#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING - bool optimize -#else - bool -#endif - ) - { - // This implementation is pretty much the same as the generic one - // except for two things: - // - // 1. When checking for the fast case, take into account long data - // columns which we may have to re-arrange. - // - // 2. Create the column list in two passes, ordinary columns first - // followed by the long data columns. - // - - bool empty (true); // Empty case (if none present). - bool fast (true); // Fast case (if all present and none are long data). - for (size_t i (0); i != bind_size && (empty || fast); ++i) - { - const bind_type& b (bind[i]); - - if (b.buffer != 0) - empty = false; - else - fast = false; - - if (b.type == bind_type::long_string || - b.type == bind_type::long_nstring || - b.type == bind_type::long_binary) - fast = false; - } - - // Empty. - // - if (empty) - { - r.clear (); - -#ifdef LIBODB_TRACE_STATEMENT_PROCESSING - if (*s != '\0') - cerr << endl - << "old: '" << s << "'" << endl << endl - << "new: '" << r << "'" << endl << endl; -#endif - return; - } - - // Fast path: just remove the "structure". - // -#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING - if (fast && !optimize) - { - process_fast (s, r); - return; - } -#endif - - // Scan the statement and store the positions of various parts. - // - size_t n (traits::length (s)); - const char* e (s + n); - - // Header. - // - const char* p (find (s, e, '\n')); - assert (p != 0); - size_t header_size (p - s); - p++; - - // Column list. - // - const char* columns_begin (p); - for (const char* ce (comma_begin (p, e)); ce != 0; comma_next (p, ce, e)) - ; - - // FROM. - assert (traits::compare (p, "FROM ", 5) == 0); - const char* from_begin (p); - p = find (p, e, '\n'); // May not end with '\n'. - if (p == 0) - p = e; - size_t from_size (p - from_begin); - if (p != e) - p++; - - // JOIN list. - // - const char* joins_begin (0), *joins_end (0); - if (e - p > 5 && fuzzy_prefix (p, e, "JOIN ", 5)) - { - joins_begin = p; - - // Find the end of the JOIN list. - // - for (const char* je (newline_begin (p, e)); - je != 0; newline_next (p, je, e, "JOIN ", 5, true)) - ; - - joins_end = (p != e ? p - 1 : p); - } - -#ifndef LIBODB_DEBUG_STATEMENT_PROCESSING - if (fast && joins_begin == 0) - { - // No JOINs to optimize so can still take the fast path. - // - process_fast (s, r); - return; - } -#endif - - // Trailer (WHERE, ORDER BY, etc). - // - const char* trailer_begin (0); - size_t trailer_size (0); - if (e - p != 0) - { - trailer_begin = p; - trailer_size = e - p; - } - - // Assume the same size as the original. It can only shrink, and in - // most cases only slightly. So this is a good approximation. - // - r.reserve (n); - r.assign (s, header_size); - - // Column list. - // - { - r += ' '; - - size_t i (0); - bool need_second (false); - - // First pass: non-long data columns. - // - { - size_t bi (0); - for (const char *c (columns_begin), *ce (comma_begin (c, e)); - ce != 0; comma_next (c, ce, e)) - { - const bind_type& b (bind[bi++]); - - // See if the column is present in the bind array and if it - // is of the right kind. - // - if (b.buffer == 0) - continue; - - if (b.type == bind_type::long_string || - b.type == bind_type::long_nstring || - b.type == bind_type::long_binary) - { - need_second = true; - continue; - } - - // Append the column. - // - if (i++ != 0) - r += ", "; // Add the space for consistency with the fast path. - - r.append (c, ce - c); - } - } - - // Second pass: long data columns. - // - if (need_second) - { - size_t bi (0); - for (const char *c (columns_begin), *ce (comma_begin (c, e)); - ce != 0; comma_next (c, ce, e)) - { - const bind_type& b (bind[bi++]); - - // See if the column is present in the bind array and if it - // is of the right kind. - // - if (b.buffer == 0 || - (b.type != bind_type::long_string && - b.type != bind_type::long_nstring && - b.type != bind_type::long_binary)) - continue; - - // Append the column. - // - if (i++ != 0) - r += ", "; // Add the space for consistency with the fast path. - - r.append (c, ce - c); - } - } - } - - // From. - // - r += ' '; - r.append (from_begin, from_size); - - // JOIN list, pass 1. - // - size_t join_pos (0); - if (joins_begin != 0) - { - // Fill in the JOIN "area" with spaces. - // - r.resize (r.size () + joins_end - joins_begin + 1, ' '); - join_pos = r.size () + 1; // End of the last JOIN. - } - - // Trailer. - // - if (trailer_size != 0) - { - r += ' '; - r.append (trailer_begin, trailer_size); - } - - // JOIN list, pass 2. - // - if (joins_begin != 0) - { - // Splice the JOINs into the pre-allocated area. - // - for (const char* je (joins_end), *j (newline_rbegin (je, joins_begin)); - j != 0; newline_rnext (j, je, joins_begin)) - { - size_t n (je - j); - - // Get the alias or, if none used, the table name. - // - p = find (j, je, "JOIN ", 5) + 5; // Skip past "JOIN ". - const char* table_begin (p); - p = find (p, je, ' '); // End of the table name. - const char* table_end (p); - p++; // Skip space. - - // We may or may not have the AS keyword. - // - const char* alias_begin (0); - size_t alias_size (0); - if (p != je && // Not the end. - (je - p < 4 || traits::compare (p, "ON ", 3) != 0)) - { - // Something other than "ON ", so got to be an alias. - // - p += 3; - alias_begin = p; - p = find (p, je, ' '); // There might be no ON (CROSS JOIN). - alias_size = (p != 0 ? p : je) - alias_begin; - } - else - { - // Just the table. - // - alias_begin = table_begin; - alias_size = table_end - alias_begin; - } - - // The alias must be quoted. - // - assert (*alias_begin == '[' && - *(alias_begin + alias_size - 1) == ']'); - - // We now need to see if the alias is used in either the SELECT - // list, the WHERE conditions, or the ON condition of any of the - // JOINs that we have already processed and decided to keep. - // - // Instead of re-parsing the whole thing again, we are going to - // take a shortcut and simply search for the alias in the statement - // we have constructed so far (that's why we have added the - // trailer before filling in the JOINs). To make it more robust, - // we are going to do a few extra sanity checks, specifically, - // that the alias is a top level identifier and is followed by - // only a single identifer (column). This will catch cases like - // [s].[t].[c] where [s] is also used as an alias or LEFT JOIN [t] - // where [t] is also used as an alias in another JOIN. - // - bool found (false); - for (size_t p (r.find (alias_begin, 0, alias_size)); - p != string::npos; - p = r.find (alias_begin, p + alias_size, alias_size)) - { - size_t e (p + alias_size); - - // If we are not a top-level qualifier or not a bottom-level, - // then we are done (3 is for at least "[a]"). - // - if ((p != 0 && r[p - 1] == '.') || - (e + 3 >= r.size () || (r[e] != '.' || r[e + 1] != '['))) - continue; - - // The only way to distinguish the [a].[c] from FROM [a].[c] or - // JOIN [a].[c] is by checking the prefix. - // - if ((p > 5 && r.compare (p - 5, 5, "FROM ") == 0) || - (p > 5 && r.compare (p - 5, 5, "JOIN ") == 0)) - continue; - - // Check that we are followed by a single identifier. - // - e = r.find (']', e + 2); - if (e == string::npos || (e + 1 != r.size () && r[e + 1] == '.')) - continue; - - found = true; - break; - } - - join_pos -= n + 1; // Extra one for space. - if (found) - r.replace (join_pos, n, j, n); - else - r.erase (join_pos - 1, n + 1); // Extra one for space. - } - } - -#ifdef LIBODB_TRACE_STATEMENT_PROCESSING - if (r.size () != n) - cerr << endl - << "old: '" << s << "'" << endl << endl - << "new: '" << r << "'" << endl << endl; -#endif - } - } -} diff --git a/odb/mssql/statement.cxx b/odb/mssql/statement.cxx deleted file mode 100644 index ede4bb6..0000000 --- a/odb/mssql/statement.cxx +++ /dev/null @@ -1,1740 +0,0 @@ -// file : odb/mssql/statement.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include // std::strlen, std::strstr, std::memset, std::memcpy -#include - -#include - -#include -#include -#include -#include -#include -#include - -using namespace std; - -namespace odb -{ - namespace mssql - { - // Mapping of bind::buffer_type to SQL_* SQL types. - // - static const SQLSMALLINT sql_type_lookup [bind::last] = - { - SQL_BIT, // bind::bit - SQL_TINYINT, // bind::tinyint - SQL_SMALLINT, // bind::smallint - SQL_INTEGER, // bind::int_ - SQL_BIGINT, // bind::bigint - - SQL_DECIMAL, // bind::decimal - SQL_DECIMAL, // bind::smallmoney - SQL_DECIMAL, // bind::money - - SQL_FLOAT, // bind::float4 - SQL_FLOAT, // bind::float8 - - SQL_VARCHAR, // bind::string - SQL_VARCHAR, // bind::long_string - - SQL_WVARCHAR, // bind::nstring - SQL_WVARCHAR, // bind::long_nstring - - SQL_VARBINARY, // bind::binary - SQL_VARBINARY, // bind::long_binary - - SQL_TYPE_DATE, // bind::date - SQL_SS_TIME2, // bind::time - SQL_TYPE_TIMESTAMP, // bind::datetime - SQL_SS_TIMESTAMPOFFSET, // bind::datetimeoffset - - SQL_GUID, // bind::uniqueidentifier - SQL_BINARY // bind::rowversion - }; - - // Mapping of bind::buffer_type to SQL_C_* C types. - // - static const SQLSMALLINT c_type_lookup [bind::last] = - { - SQL_C_BIT, // bind::bit - SQL_C_UTINYINT, // bind::tinyint - SQL_C_SSHORT, // bind::smallint - SQL_C_SLONG, // bind::int_ - SQL_C_SBIGINT, // bind::bigint - - SQL_C_NUMERIC, // bind::decimal - SQL_C_BINARY, // bind::smallmoney - SQL_C_BINARY, // bind::money - - SQL_C_FLOAT, // bind::float4 - SQL_C_DOUBLE, // bind::float8 - - SQL_C_CHAR, // bind::string - SQL_C_CHAR, // bind::long_string - - SQL_C_WCHAR, // bind::nstring - SQL_C_WCHAR, // bind::long_nstring - - SQL_C_BINARY, // bind::binary - SQL_C_BINARY, // bind::long_binary - - SQL_C_TYPE_DATE, // bind::date - SQL_C_BINARY, // bind::time - SQL_C_TYPE_TIMESTAMP, // bind::datetime - SQL_C_BINARY, // bind::datetimeoffset - - SQL_C_GUID, // bind::uniqueidentifier - SQL_C_BINARY // bind::rowversion - }; - - // Mapping of bind::buffer_type to fixed buffer capacity values. - // - static const SQLLEN capacity_lookup [bind::last] = - { - 1, // bind::bit - 1, // bind::tinyint - 2, // bind::smallint - 4, // bind::int_ - 8, // bind::bigint - - sizeof (decimal), // bind::decimal - 4, // bind::smallmoney - 8, // bind::money - - 4, // bind::float4 - 8, // bind::float8 - - 0, // bind::string - 0, // bind::long_string - - 0, // bind::nstring - 0, // bind::long_nstring - - 0, // bind::binary - 0, // bind::long_binary - - sizeof (date), // bind::date - sizeof (time), // bind::time - sizeof (datetime), // bind::datetime - sizeof (datetimeoffset), // bind::datetimeoffset - - 16, // bind::uniqueidentifier - 8 // bind::rowversion - }; - - // - // statement - // - - statement:: - statement (connection_type& conn, - const string& text, - statement_kind sk, - const binding* process, - bool optimize) - : conn_ (conn) - { - if (process == 0) - { - text_copy_ = text; - text_ = text_copy_.c_str (); - } - else - text_ = text.c_str (); // Temporary, see init(). - - init (text.size (), sk, process, optimize); - } - - statement:: - statement (connection_type& conn, - const char* text, - statement_kind sk, - const binding* process, - bool optimize, - bool copy) - : conn_ (conn) - { - size_t n; - - if (process == 0 && copy) - { - text_copy_ = text; - text_ = text_copy_.c_str (); - n = text_copy_.size (); - } - else - { - text_ = text; - n = strlen (text_); // Potentially temporary, see init(). - } - - init (n, sk, process, optimize); - } - - void statement:: - init (size_t text_size, - statement_kind sk, - const binding* proc, - bool optimize) - { - if (proc != 0) - { - switch (sk) - { - case statement_select: - process_select (text_copy_, - text_, - proc->bind, proc->count, - optimize); - break; - case statement_insert: - process_insert (text_copy_, - text_, - &proc->bind->buffer, proc->count, sizeof (bind), - '?'); - break; - case statement_update: - process_update (text_copy_, - text_, - &proc->bind->buffer, proc->count, sizeof (bind), - '?'); - break; - case statement_delete: - assert (false); - } - - text_ = text_copy_.c_str (); - text_size = text_copy_.size (); - } - - // Empty statement. - // - if (*text_ == '\0') - return; - - SQLRETURN r; - - // Allocate the handle. - // - { - SQLHANDLE h; - r = SQLAllocHandle (SQL_HANDLE_STMT, conn_.handle (), &h); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_); - - stmt_.reset (h); - } - - // Disable escape sequences. - // - r = SQLSetStmtAttr (stmt_, - SQL_ATTR_NOSCAN, - (SQLPOINTER) SQL_NOSCAN_OFF, - 0); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - { - odb::tracer* t; - if ((t = conn_.transaction_tracer ()) || - (t = conn_.tracer ()) || - (t = conn_.database ().tracer ())) - t->prepare (conn_, *this); - } - - // Prepare the statement. - // - r = SQLPrepareA (stmt_, (SQLCHAR*) text_, (SQLINTEGER) text_size); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - - statement:: - ~statement () - { - if (stmt_ != 0) - { - odb::tracer* t; - if ((t = conn_.transaction_tracer ()) || - (t = conn_.tracer ()) || - (t = conn_.database ().tracer ())) - t->deallocate (conn_, *this); - } - } - - const char* statement:: - text () const - { - return text_; - } - - void statement:: - bind_param (bind* b, size_t n) - { - SQLRETURN r; - - SQLUSMALLINT i (0); - for (bind* end (b + n); b != end; ++b) - { - if (b->buffer == 0) // Skip NULL entries. - continue; - - i++; // Column index is 1-based. - - SQLULEN col_size (0); - SQLSMALLINT digits (0); - SQLPOINTER buf; - - switch (b->type) - { - case bind::decimal: - { - buf = (SQLPOINTER) b->buffer; - col_size = (SQLULEN) (b->capacity / 100); // precision - digits = (SQLSMALLINT) (b->capacity % 100); // scale - break; - } - case bind::smallmoney: - { - buf = (SQLPOINTER) b->buffer; - col_size = 10; - digits = 4; - break; - } - case bind::money: - { - buf = (SQLPOINTER) b->buffer; - col_size = 19; - digits = 4; - break; - } - case bind::float4: - case bind::float8: - { - buf = (SQLPOINTER) b->buffer; - col_size = (SQLULEN) b->capacity; // precision - break; - } - case bind::long_string: - case bind::long_binary: - { - buf = (SQLPOINTER) b->buffer; - col_size = b->capacity != 0 - ? (SQLULEN) b->capacity - : SQL_SS_LENGTH_UNLIMITED; - break; - } - case bind::long_nstring: - { - buf = (SQLPOINTER) b->buffer; - col_size = b->capacity != 0 - ? (SQLULEN) b->capacity / 2 // In characters, not bytes. - : SQL_SS_LENGTH_UNLIMITED; - break; - } - case bind::string: - { - buf = (SQLPOINTER) b->buffer; - col_size = b->capacity != 0 - ? (SQLULEN) b->capacity - 1 // Sans the null-terminator. - : SQL_SS_LENGTH_UNLIMITED; - break; - } - case bind::binary: - { - buf = (SQLPOINTER) b->buffer; - col_size = b->capacity != 0 - ? (SQLULEN) b->capacity - : SQL_SS_LENGTH_UNLIMITED; - break; - } - case bind::nstring: - { - buf = (SQLPOINTER) b->buffer; - col_size = b->capacity != 0 - // In characters, not bytes, and sans the null-terminator. - ? (SQLULEN) (b->capacity / 2 - 1) - : SQL_SS_LENGTH_UNLIMITED; - break; - } - case bind::date: - { - buf = (SQLPOINTER) b->buffer; - // Native Client 10.0 requires the correct precision. - // - col_size = 10; - break; - } - case bind::time: - { - buf = (SQLPOINTER) b->buffer; - digits = (SQLSMALLINT) b->capacity; - - // Native Client 10.0 requires the correct precision. - // - if (digits == 0) - col_size = 8; - else - col_size = (SQLULEN) (digits + 9); - - break; - } - case bind::datetime: - { - buf = (SQLPOINTER) b->buffer; - digits = (SQLSMALLINT) b->capacity; - - // Native Client 10.0 requires the correct precision. - // - if (digits == 0) - col_size = 19; - else if (digits == 8) - { - // This is a SMALLDATETIME column which only has the minutes - // precision. Documentation indicates that the correct numeric - // precision value for this type is 16. - // - digits = 0; - col_size = 16; - } - else - col_size = (SQLULEN) (digits + 20); - - break; - } - case bind::datetimeoffset: - { - buf = (SQLPOINTER) b->buffer; - digits = (SQLSMALLINT) b->capacity; - - // Native Client 10.0 requires the correct precision. - // - if (digits == 0) - col_size = 26; - else - col_size = (SQLULEN) (digits + 27); - - break; - } - case bind::rowversion: - { - buf = (SQLPOINTER) b->buffer; - col_size = 8; - break; - } - default: - { - buf = (SQLPOINTER) b->buffer; - break; - } - } - - r = SQLBindParameter ( - stmt_, - i, - SQL_PARAM_INPUT, - c_type_lookup[b->type], - sql_type_lookup[b->type], - col_size, - digits, - buf, - 0, // buffer capacity (shouldn't be needed for input parameters) - b->size_ind); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - } - - SQLUSMALLINT statement:: - bind_result (bind* b, size_t n, SQLUSMALLINT& long_count) - { - long_count = 0; - SQLRETURN r; - - SQLUSMALLINT i (0); - for (bind* end (b + n); b != end; ++b) - { - if (b->buffer == 0) // Skip NULL entries. - continue; - - SQLLEN cap (capacity_lookup[b->type]); - - switch (b->type) - { - case bind::string: - case bind::nstring: - case bind::binary: - { - cap = b->capacity; - break; - } - case bind::long_string: - case bind::long_nstring: - case bind::long_binary: - { - // Long data is not bound. - // - long_count++; - continue; - } - case bind::last: - { - assert (false); - break; - } - default: - break; - } - - r = SQLBindCol (stmt_, - ++i, // Column index is 1-based. - c_type_lookup[b->type], - (SQLPOINTER) b->buffer, - cap, - b->size_ind); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - - return i; - } - - SQLRETURN statement:: - execute () - { - { - odb::tracer* t; - if ((t = conn_.transaction_tracer ()) || - (t = conn_.tracer ()) || - (t = conn_.database ().tracer ())) - t->execute (conn_, *this); - } - - SQLRETURN r (SQLExecute (stmt_)); - - if (r == SQL_NEED_DATA) - { - details::buffer& tmp_buf (conn_.long_data_buffer ()); - - if (tmp_buf.capacity () == 0) - tmp_buf.capacity (4096); - - long_callback* pcb; - for (;;) - { - // ODBC seems to already offset the returned pointer for us - // in case of a batch. - // - r = SQLParamData (stmt_, (SQLPOINTER*) &pcb); - - // If we get anything other than SQL_NEED_DATA, then this is - // the return code of SQLExecute(). - // - if (r != SQL_NEED_DATA) - break; - - // Store the pointer to the long_callback struct in buf on the - // first call to the callback. This allows the callback to - // redirect further calls to some other callback. - // - long_callback cb (*pcb); - const void* buf (&cb); - - size_t position (0); - for (;;) - { - size_t n; - chunk_type chunk; - - cb.callback.param ( - cb.context.param, - &position, - &buf, - &n, - &chunk, - tmp_buf.data (), - tmp_buf.capacity ()); - - r = SQLPutData ( - stmt_, - (SQLPOINTER) (buf != 0 ? buf : &buf), // Always pass non-NULL. - chunk != chunk_null ? (SQLLEN) n : SQL_NULL_DATA); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - if (chunk == chunk_one || - chunk == chunk_last || - chunk == chunk_null) - break; - } - } - } - - return r; - } - - void statement:: - stream_result (SQLUSMALLINT i, bind* b, size_t n, void* obase, void* nbase) - { - details::buffer& tmp_buf (conn_.long_data_buffer ()); - - if (tmp_buf.capacity () == 0) - tmp_buf.capacity (4096); - - SQLRETURN r; - - for (bind* end (b + n); b != end; ++b) - { - if (b->buffer == 0) // Skip NULL entries. - continue; - - bool char_data; - switch (b->type) - { - case bind::long_string: - case bind::long_nstring: - { - char_data = true; - break; - } - case bind::long_binary: - { - char_data = false; - break; - } - default: - { - continue; // Not long data. - } - } - - void* cbp; - - if (obase == 0) - cbp = b->buffer; - else - { - // Re-base the pointer. - // - char* p (static_cast (b->buffer)); - char* ob (static_cast (obase)); - char* nb (static_cast (nbase)); - - assert (ob <= p); - cbp = nb + (p - ob); - } - - long_callback cb (*static_cast (cbp)); - - // First determine if the value is NULL as well as try to - // get the total data size. - // - SQLLEN si; - r = SQLGetData (stmt_, - ++i, - c_type_lookup[b->type], - tmp_buf.data (), // Dummy value. - 0, - &si); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - // Store the pointer to the long_callback struct in buf on the - // first call to the callback. This allows the callback to - // redirect further calls to some other callback. - // - void* buf (&cb); - size_t size (0); - size_t position (0); - size_t size_left (si == SQL_NO_TOTAL ? 0 : static_cast (si)); - - chunk_type c (si == SQL_NULL_DATA - ? chunk_null - : (si == 0 ? chunk_one : chunk_first)); - - for (;;) - { - cb.callback.result ( - cb.context.result, - &position, - &buf, - &size, - c, - size_left, - tmp_buf.data (), - tmp_buf.capacity ()); - - if (c == chunk_last || c == chunk_one || c == chunk_null) - break; - - // SQLGetData() can keep returning SQL_SUCCESS_WITH_INFO (truncated) - // with SQL_NO_TOTAL for all the calls except the last one. For the - // last call we should get SQL_SUCCESS and the size_indicator should - // contain a valid value. - // - r = SQLGetData (stmt_, - i, - c_type_lookup[b->type], - (SQLPOINTER) buf, - (SQLLEN) size, - &si); - - if (r == SQL_SUCCESS) - { - assert (si != SQL_NO_TOTAL); - - // Actual amount of data copied to the buffer (appears not to - // include the NULL terminator). - // - size = static_cast (si); - c = chunk_last; - } - else if (r == SQL_SUCCESS_WITH_INFO) - { - if (char_data) - size--; // NULL terminator. - - c = chunk_next; - } - else - translate_error (r, conn_, stmt_); - - // Update the total. - // - if (size_left != 0) - size_left -= size; - } - } - } - - // - // bulk_statement - // - bulk_statement:: - ~bulk_statement () {} - - void bulk_statement:: - init (size_t skip) - { - // Setup row-wise batch operation. We set the actual number of - // parameter sets in the batch in execute(). - // - SQLRETURN r; - - r = SQLSetStmtAttr (stmt_, - SQL_ATTR_PARAM_BIND_TYPE, - (SQLPOINTER) skip, - 0); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - r = SQLSetStmtAttr (stmt_, - SQL_ATTR_PARAMS_PROCESSED_PTR, - (SQLPOINTER) &processed_, - 0); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - r = SQLSetStmtAttr (stmt_, - SQL_ATTR_PARAM_STATUS_PTR, - (SQLPOINTER) status_, - 0); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - - SQLRETURN bulk_statement:: - execute (size_t n, multiple_exceptions* mex) - { - mex_ = mex; - - if (status_ != 0) - { - SQLRETURN r (SQLSetStmtAttr (stmt_, - SQL_ATTR_PARAMSET_SIZE, - (SQLPOINTER) n, - 0)); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - // Some SQL* functions would only update the status in case of - // an error. - // - memset (status_, 0, sizeof (status_[0]) * n); - } - - processed_ = 0; - SQLRETURN r (statement::execute ()); - bool ok (SQL_SUCCEEDED (r) || r == SQL_NO_DATA); - - // If we have a batch of 1 parameter set, SQL Server ODBC driver - // returns the error via SQLExecute() rather than via the status - // array even if we set all the attributes necessary for row-wise - // binding. So what we are going to do here is convert this case - // to the batch way of reporting errors (not that we also check - // processed_ so that we only do this is the parameter set was - // actually attempted). - // - if (!ok && status_ != 0 && n == 1 && processed_ == 1) - { - status_[0] = SQL_PARAM_ERROR; - r = SQL_SUCCESS; - ok = true; - } - - // If the statement failed as a whole, assume no parameter sets - // were attempted in case of a batch. Otherwise, the documentation - // says that the native client driver keeps processing remaining - // sets even in case of an error. - // - i_ = 0; - n_ = (ok ? n : (status_ == 0 ? 1 : 0)); - - if (mex_ != 0) - { - mex_->current (i_); - mex_->attempted (processed_); - } - - if (!ok) - { - if (mex_ != 0) - mex_->fatal (true); // An incomplete batch is always fatal. - - return r; - } - - return r; - } - - size_t bulk_statement:: - extract_errors () - { - size_t e (0); - - for (size_t i (0); i != n_; ++i) - { - if (status_[i] != SQL_PARAM_SUCCESS && - status_[i] != SQL_PARAM_SUCCESS_WITH_INFO) - { - translate_error (SQL_ERROR, conn_, stmt_, i, mex_); - e++; - } - } - - return e; - } - - unsigned long long bulk_statement:: - affected (SQLRETURN r, size_t errors, bool unique) - { - unsigned long long rows (0); - - // SQL_NO_DATA indicates that the statement hasn't affected any rows. - // - if (r != SQL_NO_DATA) - { - SQLLEN n; - r = SQLRowCount (stmt_, &n); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - // If all the parameter sets failed, then the returned count is -1, - // which means "not available" according to the documentation. - // - rows = (n != -1 ? static_cast (n) : 0); - } - - if (n_ > 1) // Batch. - { - if (rows != 0) // Some rows did get affected. - { - // Subtract the parameter sets that failed since they haven't - // affected any rows. - // - size_t p (n_ - errors); - - if (p > 1) // True batch. - { - if (unique) // Each can affect 0 or 1 row. - { - rows = (p == static_cast (rows) - ? 1 - : result_unknown); - } - else - rows = result_unknown; - } - } - } - - return rows; - } - - // - // select_statement - // - select_statement:: - ~select_statement () - { - } - - select_statement:: - select_statement (connection_type& conn, - const string& text, - bool process, - bool optimize, - binding& param, - binding& result) - : statement (conn, - text, statement_select, - (process ? &result : 0), optimize), - result_ (result) - { - if (!empty ()) - { - bind_param (param.bind, param.count); - result_count_ = bind_result (result.bind, result.count, long_count_); - } - } - - select_statement:: - select_statement (connection_type& conn, - const char* text, - bool process, - bool optimize, - binding& param, - binding& result, - bool copy_text) - : statement (conn, - text, statement_select, - (process ? &result : 0), optimize, - copy_text), - result_ (result) - { - if (!empty ()) - { - bind_param (param.bind, param.count); - result_count_ = bind_result (result.bind, result.count, long_count_); - } - } - - select_statement:: - select_statement (connection_type& conn, - const string& text, - bool process, - bool optimize, - binding& result) - : statement (conn, - text, statement_select, - (process ? &result : 0), optimize), - result_ (result) - { - if (!empty ()) - result_count_ = bind_result (result.bind, result.count, long_count_); - } - - select_statement:: - select_statement (connection_type& conn, - const char* text, - bool process, - bool optimize, - binding& result, - bool copy_text) - : statement (conn, - text, statement_select, - (process ? &result : 0), optimize, - copy_text), - result_ (result) - { - if (!empty ()) - result_count_ = bind_result (result.bind, result.count, long_count_); - } - - void select_statement:: - execute () - { - SQLRETURN r (statement::execute ()); - - // Skip empty result sets that seem to be added as a result of - // executing DML statements in stored procedures (e.g., INSERT - // INTO EXEC). - // - if (r == SQL_NO_DATA) - { - r = SQLMoreResults (stmt_); - - if (r == SQL_NO_DATA) - { - throw database_exception ( - 0, - "?????", - "another result set expected after SQL_NO_DATA"); - } - } - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - // Skip result sets that have no columns. These seem to be added - // by DML statements that don't produce any result (e.g., EXEC). - // - for (columns_ = 0; columns_ == 0;) - { - { - SQLSMALLINT c; - r = SQLNumResultCols (stmt_, &c); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - columns_ = static_cast (c); - } - - if (columns_ == 0) - { - r = SQLMoreResults (stmt_); - - if (r == SQL_NO_DATA) - break; - else if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - } - - // Make sure that the number of columns in the result returned by - // the database matches the number that we expect. A common cause - // of this assertion is a native view with a number of data members - // not matching the number of columns in the SELECT-list. - // - assert (columns_ == result_count_ + long_count_); - } - - select_statement::result select_statement:: - fetch () - { - change_callback* cc (result_.change_callback); - - if (cc != 0 && cc->callback != 0) - (cc->callback) (cc->context); - - // Don't bother calling SQLFetch() if there are no columns. - // - if (columns_ == 0) - return no_data; - else - { - SQLRETURN r (SQLFetch (stmt_)); - - if (r == SQL_NO_DATA) - return no_data; - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - return success; - } - } - - void select_statement:: - free_result () - { - // Use SQLFreeStmt(SQL_CLOSE) instead of SQLCloseCursor() to avoid an - // error if a cursor is already closed. This can happens, for example, - // if we are trying to close the cursor after the transaction has been - // committed (e.g., when destroying the query result) which also closes - // the cursor. - // - SQLRETURN r (SQLFreeStmt (stmt_, SQL_CLOSE)); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - - // - // insert_statement - // - - insert_statement:: - ~insert_statement () - { - } - - insert_statement:: - insert_statement (connection_type& conn, - const string& text, - bool process, - binding& param, - bool returning_id, - bool returning_version, - binding* returning) - : bulk_statement (conn, - text, statement_insert, - (process ? ¶m : 0), false, - param.batch, param.skip, param.status), - returning_id_ (returning_id), - returning_version_ (returning_version), - ret_ (returning) - { - bind_param (param.bind, param.count); - - if (ret_ != 0) - init_result (); - } - - insert_statement:: - insert_statement (connection_type& conn, - const char* text, - bool process, - binding& param, - bool returning_id, - bool returning_version, - binding* returning, - bool copy_text) - : bulk_statement (conn, - text, statement_insert, - (process ? ¶m : 0), false, - param.batch, param.skip, param.status, - copy_text), - returning_id_ (returning_id), - returning_version_ (returning_version), - ret_ (returning) - { - bind_param (param.bind, param.count); - - if (ret_ != 0) - init_result (); - } - - template - static inline T* - offset (T* base, size_t count, size_t size) - { - return reinterpret_cast ( - reinterpret_cast (base) + count * size); - } - - void insert_statement:: - init_result () - { - // Figure out if we are using the OUTPUT clause or a batch of - // INSERT and SELECT statements. The latter is used to work - // around a bug in SQL Server 2005 that causes it to fail - // on an INSERT statement with the OUTPUT clause if data - // for one of the inserted columns is supplied at execution - // (long data). - // - text_batch_ = (strstr (text_, "OUTPUT INSERTED.") == 0 && - strstr (text_, "output inserted.") == 0); - - // It might seem logical to set up the array of results if this is a - // batch (i.e., the SQL_ATTR_ROW_BIND_TYPE, SQL_ATTR_ROW_ARRAY_SIZE). - // This won't work because what we are getting is multiple result - // sets (each containing a single row) and not multiple rows. As a - // result, the SQL Server ODBC driver will always store the data in - // the first element of our array. A bit counter-intuitive. - // - // At the same time it would be conceptually cleaner to have the - // returned data extracted into the batch array instead of always - // the first element. This is also how other database runtimes (e.g., - // Oracle) behave. So what we are going to do here is emulate this - // by making the ODBC driver store the data into the last element - // of the batch array and then copying it into the right place - // after processing each result set (see fetch() below). - // - SQLRETURN r; - SQLUSMALLINT col (1); - - size_t last (ret_->batch - 1); - - if (returning_id_) - { - bind& b (ret_->bind[0]); // Auto id is the first element. - - r = SQLBindCol (stmt_, - col++, - c_type_lookup[b.type], - (SQLPOINTER) offset (b.buffer, last, ret_->skip), - capacity_lookup[b.type], - offset (b.size_ind, last, ret_->skip)); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - - if (returning_version_) - { - bind& b (ret_->bind[ret_->count - 1]); // Version is the last element. - - r = SQLBindCol (stmt_, - col++, - c_type_lookup[b.type], - (SQLPOINTER) offset (b.buffer, last, ret_->skip), - capacity_lookup[b.type], - offset (b.size_ind, last, ret_->skip)); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - } - - size_t insert_statement:: - execute (size_t n, multiple_exceptions* mex) - { - // The batch INSERT works in two different ways, depending on - // whether we have the OUTPUT clause. If there is no OUTPUT, then - // all the parameter sets are processed inside the SQLExecute() - // call. If, however, there is OUTPUT, then the sets are - // processed one at a time as we consume the results with - // the SQLMoreResults() call below. Thus we in effect have - // two counts: the "processed so far" as set by the API - // (SQL_ATTR_PARAMS_PROCESSED_PTR) and the "to be processed" - // (value in n_). Note that in the OUTPUT case if there is an - // error, the processed count seems to jump by 2 for some reason. - // - // The OUTPUT case can be handled in two different ways: we can - // "execute" (with SQLMoreResults()) each set as the user moves - // from one result to the next (result() call). The advantage of - // this approach is that the returned data ends up in the right - // place automatically. The potential drawback is that the total - // affected row count will only be available at the end. As a - // result, this approach probably won't work if we need to handle, - // say, UPDATE with OUTPUT (SQLRowCount() does not return an - // intermediate total, at least not for INSERT). - // - // The alternative implementation would call SQLMoreResults() - // inside execute() until all the parameter sets are executed. - // In this case we will have to copy the extracted data into - // the right place in the bindings (or update the binding before - // each call to SQLMoreResults()). It is also not clear whether - // the diagnostic records for the failed sets would accumulate. - // If not, those will have to be stashed into mex on each - // iteration. - // - SQLRETURN r (bulk_statement::execute (n, mex)); - - // Statement failed as a whole, assume no parameter sets were - // attempted in case of a batch. - // - if (!SQL_SUCCEEDED (r)) - { - fetch (r); - return n_; - } - - if (status_ == 0) // Non-batch case. - fetch (SQL_SUCCESS); - else - fetch (status_[i_] == SQL_PARAM_SUCCESS || - status_[i_] == SQL_PARAM_SUCCESS_WITH_INFO - ? SQL_SUCCESS : SQL_ERROR); - - return n_; - } - - void insert_statement:: - fetch (SQLRETURN r) - { - result_ = true; - - if (!SQL_SUCCEEDED (r)) - { - // An auto-assigned object id should never cause a duplicate primary - // key. - // - if (!returning_id_) - { - // Translate the integrity contraint violation (SQLSTATE 23000) - // to the false result value. This code is similar to that found - // in translate_error(). - // - char sqlstate[SQL_SQLSTATE_SIZE + 1]; - SQLINTEGER native_code; - SQLSMALLINT msg_size; - - bool cv (false); - - for (SQLSMALLINT i (1);; ++i) - { - SQLRETURN r; - - // Filter based on row association. - // - if (mex_ != 0) - { - SQLLEN n; - r = SQLGetDiagField (SQL_HANDLE_STMT, - stmt_, - i, - SQL_DIAG_ROW_NUMBER, - &n, - 0, - 0); - - if (r == SQL_NO_DATA) - break; - else if (!SQL_SUCCEEDED (r)) - continue; - - if (n == SQL_NO_ROW_NUMBER || - n == SQL_ROW_NUMBER_UNKNOWN || - n != static_cast (i_ + 1)) // 1-based - continue; - } - - r= SQLGetDiagRecA (SQL_HANDLE_STMT, - stmt_, - i, - (SQLCHAR*) sqlstate, - &native_code, - 0, - 0, - &msg_size); - - if (r == SQL_NO_DATA) - break; - else if (SQL_SUCCEEDED (r)) - { - string s (sqlstate); - - if (s == "23000") // Integrity contraint violation. - cv = true; - else if (s != "01000") // General warning. - { - // Some other code. - // - cv = false; - break; - } - } - else // SQLGetDiagRec() failure. - { - cv = false; - break; - } - } - - if (cv) - result_ = false; - } - - if (result_) - { - translate_error (r, conn_, stmt_, i_, mex_); // Can return. - result_ = false; // Prevent id/version extraction below or. - } - } - - // Fetch the row containing the id/version if this statement is - // returning. - // - if (result_ && ret_ != 0) - { - if (text_batch_) - { - r = SQLMoreResults (stmt_); - - if (r == SQL_NO_DATA) - { - throw database_exception ( - 0, - "?????", - "multiple result sets expected from a batch of statements"); - } - else if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - - r = SQLFetch (stmt_); - - if (r != SQL_NO_DATA && !SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - if (r == SQL_NO_DATA) - throw database_exception ( - 0, - "?????", - "result set expected from a statement with the OUTPUT clause"); - - // See init_result() for details on what's going here. - // - size_t last (ret_->batch - 1); - if (i_ != last) - { - if (returning_id_) - { - bind& b (ret_->bind[0]); // Auto id is the first element. - - memcpy (offset (b.buffer, i_, ret_->skip), - offset (b.buffer, last, ret_->skip), - capacity_lookup[b.type]); - - memcpy (offset (b.size_ind, i_, ret_->skip), - offset (b.size_ind, last, ret_->skip), - sizeof (*b.size_ind)); - } - - if (returning_version_) - { - bind& b (ret_->bind[ret_->count - 1]); // Version is the last. - - memcpy (offset (b.buffer, i_, ret_->skip), - offset (b.buffer, last, ret_->skip), - capacity_lookup[b.type]); - - memcpy (offset (b.size_ind, i_, ret_->skip), - offset (b.size_ind, last, ret_->skip), - sizeof (*b.size_ind)); - } - } - } - } - - bool insert_statement:: - result (size_t i) - { - assert ((i_ == i || i_ + 1 == i) && i < n_); - - SQLRETURN r; - - // Get to the next result set if necessary. - // - if (i != i_) - { - mex_->current (++i_); // mex cannot be NULL since this is a batch. - - // Only in case of the OUTPUT clause do we have multiple result sets. - // - if (ret_ != 0) - { - r = SQLMoreResults (stmt_); - - // The actually processed count could have changed (see execute()). - // - mex_->attempted (processed_); - - if (r == SQL_NO_DATA) - { - throw database_exception ( - 0, - "?????", - "multiple result sets expected from an array of parameters"); - } - } - - fetch (status_[i_] == SQL_PARAM_SUCCESS || - status_[i_] == SQL_PARAM_SUCCESS_WITH_INFO - ? SQL_SUCCESS : SQL_ERROR); - } - - // Close the cursor if we are done. - // - if (ret_ != 0 && i_ + 1 == n_) - { - // Use SQLFreeStmt(SQL_CLOSE) instead of SQLCloseCursor() to avoid - // an error if a cursor is not open. This seem to happen if the - // statement failure was translated to a parameter set failure in - // bulk_statement for batches of one. - // - r = SQLFreeStmt (stmt_, SQL_CLOSE); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - - return result_; - } - - // - // update_statement - // - - update_statement:: - ~update_statement () - { - } - - update_statement:: - update_statement (connection_type& conn, - const string& text, - bool process, - binding& param, - binding* returning) - : bulk_statement (conn, - text, statement_update, - (process ? ¶m : 0), false, - param.batch, param.skip, param.status), - unique_ (false), - returning_ (returning != 0) - { - assert (param.batch == 1); // Specify unique_hint explicitly. - init (param, returning); - } - - update_statement:: - update_statement (connection_type& conn, - const string& text, - bool unique, - bool process, - binding& param, - binding* returning) - : bulk_statement (conn, - text, statement_update, - (process ? ¶m : 0), false, - param.batch, param.skip, param.status), - unique_ (unique), - returning_ (returning != 0) - { - init (param, returning); - } - - update_statement:: - update_statement (connection_type& conn, - const char* text, - bool process, - binding& param, - binding* returning, - bool copy_text) - : bulk_statement (conn, - text, statement_update, - (process ? ¶m : 0), false, - param.batch, param.skip, param.status, - copy_text), - unique_ (false), - returning_ (returning != 0) - { - assert (param.batch == 1); // Specify unique_hint explicitly. - init (param, returning); - } - - update_statement:: - update_statement (connection_type& conn, - const char* text, - bool unique, - bool process, - binding& param, - binding* returning, - bool copy_text) - : bulk_statement (conn, - text, statement_update, - (process ? ¶m : 0), false, - param.batch, param.skip, param.status, - copy_text), - unique_ (unique), - returning_ (returning != 0) - { - init (param, returning); - } - - void update_statement:: - init (binding& param, binding* ret) - { - if (!empty ()) - { - bind_param (param.bind, param.count); - - if (ret != 0) - { - bind& b (ret->bind[ret->count - 1]); // Version is the last element. - - SQLRETURN r (SQLBindCol (stmt_, - 1, - c_type_lookup[b.type], - (SQLPOINTER) b.buffer, - capacity_lookup[b.type], - b.size_ind)); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - } - } - - size_t update_statement:: - execute (size_t n, multiple_exceptions* mex) - { - // In batch UPDATE without the OUTPUT clause (which is the - // only kind we currently support) all the parameter sets - // are processed inside SQLExecute() and the total count of - // affected rows is available after it returns. - // - assert (!returning_ || status_ == 0); - - SQLRETURN r (bulk_statement::execute (n, mex)); - - // Statement failed as a whole, assume no parameter sets were - // attempted in case of a batch. - // - if (!(SQL_SUCCEEDED (r) || r == SQL_NO_DATA)) - { - translate_error (r, conn_, stmt_, 0, mex_); - return n_; - } - - if (status_ == 0) // Non-batch case. - { - // Fetch the row containing the data if this statement is - // returning. We still need to close the cursor even if we - // haven't updated any rows. - // - if (returning_) - { - r = SQLFetch (stmt_); - - if (r != SQL_NO_DATA && !SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - - // We have to get the result after fetching the OUTPUT data - // but before closing the cursor. - // - result_ = affected (SQL_SUCCESS, 0, unique_); - - { - SQLRETURN r (SQLCloseCursor (stmt_)); // Don't overwrite r. - - if (!SQL_SUCCEEDED (r)) - translate_error (r, conn_, stmt_); - } - - if (result_ != 0 && r == SQL_NO_DATA) - throw database_exception ( - 0, - "?????", - "result set expected from a statement with the OUTPUT clause"); - } - else - result_ = affected (r, 0, unique_); - } - else - { - // Extract error information for failed parameter sets. If we do - // this after calling SQLRowCount(), all the diagnostics records - // that we need will be gone. - // - size_t errors (extract_errors ()); - - // Figure out the affected row count. - // - result_ = affected (r, errors, unique_); - } - - return n_; - } - - // - // delete_statement - // - - delete_statement:: - ~delete_statement () - { - } - - delete_statement:: - delete_statement (connection_type& conn, - const string& text, - binding& param) - : bulk_statement (conn, - text, statement_delete, - 0, false, - param.batch, param.skip, param.status), - unique_ (false) - { - assert (param.batch == 1); // Specify unique_hint explicitly. - bind_param (param.bind, param.count); - } - - delete_statement:: - delete_statement (connection_type& conn, - const string& text, - bool unique, - binding& param) - : bulk_statement (conn, - text, statement_delete, - 0, false, - param.batch, param.skip, param.status), - unique_ (unique) - { - bind_param (param.bind, param.count); - } - - delete_statement:: - delete_statement (connection_type& conn, - const char* text, - binding& param, - bool copy_text) - : bulk_statement (conn, - text, statement_delete, - 0, false, - param.batch, param.skip, param.status, - copy_text), - unique_ (false) - { - assert (param.batch == 1); // Specify unique_hint explicitly. - bind_param (param.bind, param.count); - } - - delete_statement:: - delete_statement (connection_type& conn, - const char* text, - bool unique, - binding& param, - bool copy_text) - : bulk_statement (conn, - text, statement_delete, - 0, false, - param.batch, param.skip, param.status, - copy_text), - unique_ (unique) - { - bind_param (param.bind, param.count); - } - - size_t delete_statement:: - execute (size_t n, multiple_exceptions* mex) - { - // In batch DELETE without the OUTPUT clause (which is the - // only kind we currently support) all the parameter sets - // are processed inside SQLExecute() and the total count of - // affected rows is available after it returns. - // - - SQLRETURN r (bulk_statement::execute (n, mex)); - - // Statement failed as a whole, assume no parameter sets were - // attempted in case of a batch. - // - if (!(SQL_SUCCEEDED (r) || r == SQL_NO_DATA)) - { - translate_error (r, conn_, stmt_, 0, mex_); - return n_; - } - - // Extract error information for failed parameter sets. If we do - // this after calling SQLRowCount(), all the diagnostics records - // that we need will be gone. - // - size_t errors (status_ != 0 ? extract_errors () : 0); - - // Figure out the affected row count. - // - result_ = affected (r, errors, unique_); - - return n_; - } - } -} diff --git a/odb/mssql/statement.hxx b/odb/mssql/statement.hxx deleted file mode 100644 index 74326a0..0000000 --- a/odb/mssql/statement.hxx +++ /dev/null @@ -1,558 +0,0 @@ -// file : odb/mssql/statement.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_STATEMENT_HXX -#define ODB_MSSQL_STATEMENT_HXX - -#include - -#include -#include // std::size_t - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - class connection; - - class LIBODB_MSSQL_EXPORT statement: public odb::statement - { - public: - typedef mssql::connection connection_type; - - virtual - ~statement () = 0; - - SQLHSTMT - handle () const - { - return stmt_; - } - - virtual const char* - text () const; - - virtual connection_type& - connection () - { - return conn_; - } - - // A statement can be empty. This is used to handle situations - // where a SELECT or UPDATE statement ends up not having any - // columns after processing. An empty statement cannot be - // executed. - // - bool - empty () const - { - return stmt_ == 0; - } - - protected: - // We keep two versions to take advantage of std::string COW. - // - statement (connection_type&, - const std::string& text, - statement_kind, - const binding* process, - bool optimize); - - statement (connection_type&, - const char* text, - statement_kind, - const binding* process, - bool optimize, - bool copy_text); - - private: - void - init (std::size_t text_size, - statement_kind, - const binding* process, - bool optimize); - - // Custom implementation for SQL Server that also moves long data - // columns to the end. - // - static void - process_select (std::string& result, - const char* statement, - const bind*, - std::size_t bind_size, - bool optimize); - - protected: - void - bind_param (bind*, std::size_t count); - - // Return the actual number of columns bound. - // - SQLUSMALLINT - bind_result (bind*, std::size_t count, SQLUSMALLINT& long_count); - - SQLRETURN - execute (); - - // The old_base and new_base arguments can be used to "re-base" - // the long_callback struct pointer (stored in bind::buffer). - // This is used by the query machinery to cause stream_result() - // to use the callback information from a copy of the image - // instead of the bound image. - // - void - stream_result (SQLUSMALLINT start_col, - bind*, - std::size_t count, - void* old_base = 0, - void* new_base = 0); - - protected: - connection_type& conn_; - std::string text_copy_; - const char* text_; - auto_handle stmt_; - }; - - class LIBODB_MSSQL_EXPORT bulk_statement: public statement - { - public: - virtual - ~bulk_statement () = 0; - - protected: - bulk_statement (connection_type&, - const std::string& text, - statement_kind, - const binding* process, - bool optimize, - std::size_t batch, - std::size_t skip, - SQLUSMALLINT* status); - - bulk_statement (connection_type&, - const char* text, - statement_kind, - const binding* process, - bool optimize, - std::size_t batch, - std::size_t skip, - SQLUSMALLINT* status, - bool copy_text); - - // Call SQLExecute() and set up the batch tracking variables (see - // below). Note that this function does not treat SQL_NO_DATA as - // an error since for DELETE and UPDATE statements this is a - // shortcut notation for zero rows affected. - // - SQLRETURN - execute (std::size_t n, multiple_exceptions*); - - // Return the number of failed parameter sets. - // - std::size_t - extract_errors (); - - static const unsigned long long result_unknown = ~0ULL; - - unsigned long long - affected (SQLRETURN, std::size_t errors, bool unique); - - private: - void - init (std::size_t skip); - - protected: - SQLULEN processed_; // Number of parameter sets processed so far. - SQLUSMALLINT* status_; // Parameter sets status array. - std::size_t n_; // Actual batch size. - std::size_t i_; // Position in result. - multiple_exceptions* mex_; - }; - - class LIBODB_MSSQL_EXPORT select_statement: public statement - { - public: - virtual - ~select_statement (); - - // While the long data columns can appear in any order in the - // result binding, they should appear last in the statement - // text. - // - select_statement (connection_type& conn, - const std::string& text, - bool process_text, - bool optimize_text, - binding& param, - binding& result); - - select_statement (connection_type& conn, - const char* text, - bool process_text, - bool optimize_text, - binding& param, - binding& result, - bool copy_text = true); - - select_statement (connection_type& conn, - const std::string& text, - bool process_text, - bool optimize_text, - binding& result); - - select_statement (connection_type& conn, - const char* text, - bool process_text, - bool optimize_text, - binding& result, - bool copy_text = true); - - enum result - { - success, - no_data - }; - - void - execute (); - - result - fetch (); - - // Return true if any long data was streamed. - // - bool - stream_result (void* old_base = 0, void* new_base = 0) - { - if (long_count_ != 0) - statement::stream_result (result_count_, - result_.bind, - result_.count, - old_base, - new_base); - return long_count_ != 0; - } - - void - free_result (); - - private: - select_statement (const select_statement&); - select_statement& operator= (const select_statement&); - - private: - binding& result_; - SQLUSMALLINT result_count_; // Actual number of columns bound. - SQLUSMALLINT long_count_; // Number of long data columns. - SQLUSMALLINT columns_; // Number of columns in result set. - }; - - struct LIBODB_MSSQL_EXPORT auto_result - { - explicit auto_result (select_statement& s): s_ (&s) {} - ~auto_result () {free ();} - - // Extended interface to support delayed freeing. - // - auto_result (): s_ (0) {} - - void - set (select_statement& s) {s_ = &s;} - - void - free () - { - if (s_ != 0) - { - s_->free_result (); - s_ = 0; - } - } - - void - release () {s_ = 0;} - - private: - auto_result (const auto_result&); - auto_result& operator= (const auto_result&); - - private: - select_statement* s_; - }; - - class LIBODB_MSSQL_EXPORT insert_statement: public bulk_statement - { - public: - virtual - ~insert_statement (); - - insert_statement (connection_type& conn, - const std::string& text, - bool process_text, - binding& param, - bool returning_id, - bool returning_version, - binding* returning); - - insert_statement (connection_type& conn, - const char* text, - bool process_text, - binding& param, - bool returning_id, - bool returning_version, - binding* returning, - bool copy_text = true); - - // Return the number of parameter sets (out of n) that were attempted. - // - std::size_t - execute (std::size_t n, multiple_exceptions& mex) - { - return execute (n, &mex); - } - - // Return true if successful and false if this row is a duplicate. - // All other errors are reported by throwing exceptions. - // - bool - result (std::size_t i); - - bool - execute () - { - execute (1, 0); - return result (0); - } - - private: - insert_statement (const insert_statement&); - insert_statement& operator= (const insert_statement&); - - private: - void - init_result (); - - std::size_t - execute (std::size_t, multiple_exceptions*); - - void - fetch (SQLRETURN); - - private: - bool returning_id_; - bool returning_version_; - binding* ret_; - bool text_batch_; - - bool result_; - }; - - class LIBODB_MSSQL_EXPORT update_statement: public bulk_statement - { - public: - virtual - ~update_statement (); - - // SQL Server native client ODBC driver does not expose individual - // affected row counts for batch operations, even though it says it - // does (SQLGetInfo(SQL_PARAM_ARRAY_ROW_COUNTS) returns SQL_PARC_BATCH). - // Instead, it adds them all up and returns a single count. This is - // bad news for us. - // - // In case of updating by primary key (the affected row count is - // either 1 or 0), we can recognize the presumably successful case - // where the total affected row count is equal to the batch size - // (we can also recognize the "all unsuccessful" case where the - // total affected row count is 0). The unique_hint argument in the - // constructors below indicates whether this is a "0 or 1" UPDATE - // statement. - // - // In all other situations (provided this is a batch), the result() - // function below returns the special result_unknown value. - // - update_statement (connection_type& conn, - const std::string& text, - bool process, - binding& param, - binding* returning); - - update_statement (connection_type& conn, - const std::string& text, - bool unique_hint, - bool process, - binding& param, - binding* returning); - - update_statement (connection_type& conn, - const char* text, - bool process, - binding& param, - binding* returning, - bool copy_text = true); - - update_statement (connection_type& conn, - const char* text, - bool unique_hint, - bool process, - binding& param, - binding* returning, - bool copy_text = true); - - // Return the number of parameter sets (out of n) that were attempted. - // - std::size_t - execute (std::size_t n, multiple_exceptions& mex) - { - return execute (n, &mex); - } - - // Return the number of rows affected (updated) by the parameter - // set. If this is a batch (n > 1 in execute() call above) and it - // is impossible to determine the affected row count for each - // parameter set, then this function returns result_unknown. All - // other errors are reported by throwing exceptions. - // - using bulk_statement::result_unknown; - - unsigned long long - result (std::size_t i) - { - if (i != i_) - mex_->current (++i_); // mex cannot be NULL since this is a batch. - - return result_; - } - - unsigned long long - execute () - { - execute (1, 0); - return result (0); - } - - private: - update_statement (const update_statement&); - update_statement& operator= (const update_statement&); - - private: - void - init (binding& param, binding* ret); - - std::size_t - execute (std::size_t, multiple_exceptions*); - - private: - bool unique_; - bool returning_; - - unsigned long long result_; - }; - - class LIBODB_MSSQL_EXPORT delete_statement: public bulk_statement - { - public: - virtual - ~delete_statement (); - - // SQL Server native client ODBC driver does not expose individual - // affected row counts for batch operations, even though it says it - // does (SQLGetInfo(SQL_PARAM_ARRAY_ROW_COUNTS) returns SQL_PARC_BATCH). - // Instead, it adds them all up and returns a single count. This is - // bad news for us. - // - // In case of deleting by primary key (the affected row count is - // either 1 or 0), we can recognize the presumably successful case - // where the total affected row count is equal to the batch size - // (we can also recognize the "all unsuccessful" case where the - // total affected row count is 0). The unique_hint argument in the - // constructors below indicates whether this is a "0 or 1" DELETE - // statement. - // - // In all other situations (provided this is a batch), the result() - // function below returns the special result_unknown value. - // - delete_statement (connection_type& conn, - const std::string& text, - binding& param); - - delete_statement (connection_type& conn, - const std::string& text, - bool unique_hint, - binding& param); - - delete_statement (connection_type& conn, - const char* text, - binding& param, - bool copy_text = true); - - delete_statement (connection_type& conn, - const char* text, - bool unique_hint, - binding& param, - bool copy_text = true); - - // Return the number of parameter sets (out of n) that were attempted. - // - std::size_t - execute (std::size_t n, multiple_exceptions& mex) - { - return execute (n, &mex); - } - - // Return the number of rows affected (deleted) by the parameter - // set. If this is a batch (n > 1 in execute() call above) and it - // is impossible to determine the affected row count for each - // parameter set, then this function returns result_unknown. All - // other errors are reported by throwing exceptions. - // - using bulk_statement::result_unknown; - - unsigned long long - result (std::size_t i) - { - if (i != i_) - mex_->current (++i_); // mex cannot be NULL since this is a batch. - - return result_; - } - - unsigned long long - execute () - { - execute (1, 0); - return result (0); - } - - private: - delete_statement (const delete_statement&); - delete_statement& operator= (const delete_statement&); - - private: - std::size_t - execute (std::size_t, multiple_exceptions*); - - private: - bool unique_; - unsigned long long result_; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_STATEMENT_HXX diff --git a/odb/mssql/statement.ixx b/odb/mssql/statement.ixx deleted file mode 100644 index 12cce80..0000000 --- a/odb/mssql/statement.ixx +++ /dev/null @@ -1,41 +0,0 @@ -// file : odb/mssql/statement.ixx -// license : ODB NCUEL; see accompanying LICENSE file - -namespace odb -{ - namespace mssql - { - inline bulk_statement:: - bulk_statement (connection_type& c, - const std::string& text, - statement_kind k, - const binding* process, - bool optimize, - std::size_t batch, - std::size_t skip, - SQLUSMALLINT* status) - : statement (c, text, k, process, optimize), - status_ (batch == 1 ? 0 : status) - { - if (status_ != 0 && !empty ()) - init (skip); - } - - inline bulk_statement:: - bulk_statement (connection_type& c, - const char* text, - statement_kind k, - const binding* process, - bool optimize, - std::size_t batch, - std::size_t skip, - SQLUSMALLINT* status, - bool copy_text) - : statement (c, text, k, process, optimize, copy_text), - status_ (batch == 1 ? 0 : status) - { - if (status_ != 0 && !empty ()) - init (skip); - } - } -} diff --git a/odb/mssql/statements-base.cxx b/odb/mssql/statements-base.cxx deleted file mode 100644 index 9f302e3..0000000 --- a/odb/mssql/statements-base.cxx +++ /dev/null @@ -1,15 +0,0 @@ -// file : odb/mssql/statements-base.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -namespace odb -{ - namespace mssql - { - statements_base:: - ~statements_base () - { - } - } -} diff --git a/odb/mssql/statements-base.hxx b/odb/mssql/statements-base.hxx deleted file mode 100644 index 4506628..0000000 --- a/odb/mssql/statements-base.hxx +++ /dev/null @@ -1,63 +0,0 @@ -// file : odb/mssql/statements-base.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_STATEMENTS_BASE_HXX -#define ODB_MSSQL_STATEMENTS_BASE_HXX - -#include - -#include -#include - -#include -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - class LIBODB_MSSQL_EXPORT statements_base: public details::shared_base - { - public: - typedef mssql::connection connection_type; - - connection_type& - connection () - { - return conn_; - } - - // Schema version. database::schema_version_migration() is thread- - // safe which means it is also slow. Cache the result in statements - // so we can avoid the mutex lock. This is thread-safe since if the - // version is updated, then the statements cache will be expired. - // - const schema_version_migration& - version_migration (const char* name = "") const - { - if (svm_ == 0) - svm_ = &conn_.database ().schema_version_migration (name); - - return *svm_; - } - - public: - virtual - ~statements_base (); - - protected: - statements_base (connection_type& conn): conn_ (conn), svm_ (0) {} - - protected: - connection_type& conn_; - mutable const schema_version_migration* svm_; - }; - } -} - -#include - -#endif // ODB_MSSQL_STATEMENTS_BASE_HXX diff --git a/odb/mssql/tracer.cxx b/odb/mssql/tracer.cxx deleted file mode 100644 index 3fe62c9..0000000 --- a/odb/mssql/tracer.cxx +++ /dev/null @@ -1,60 +0,0 @@ -// file : odb/mssql/tracer.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include -#include -#include - -namespace odb -{ - namespace mssql - { - tracer:: - ~tracer () - { - } - - void tracer:: - prepare (connection&, const statement&) - { - } - - void tracer:: - execute (connection& c, const statement& s) - { - execute (c, s.text ()); - } - - void tracer:: - deallocate (connection&, const statement&) - { - } - - void tracer:: - prepare (odb::connection& c, const odb::statement& s) - { - prepare (static_cast (c), - static_cast (s)); - } - - void tracer:: - execute (odb::connection& c, const odb::statement& s) - { - execute (static_cast (c), - static_cast (s)); - } - - void tracer:: - execute (odb::connection& c, const char* s) - { - execute (static_cast (c), s); - } - - void tracer:: - deallocate (odb::connection& c, const odb::statement& s) - { - deallocate (static_cast (c), - static_cast (s)); - } - } -} diff --git a/odb/mssql/tracer.hxx b/odb/mssql/tracer.hxx deleted file mode 100644 index feaf5f0..0000000 --- a/odb/mssql/tracer.hxx +++ /dev/null @@ -1,61 +0,0 @@ -// file : odb/mssql/tracer.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_TRACER_HXX -#define ODB_MSSQL_TRACER_HXX - -#include - -#include - -#include -#include -#include - -namespace odb -{ - namespace mssql - { - class LIBODB_MSSQL_EXPORT tracer: private odb::tracer - { - public: - virtual - ~tracer (); - - virtual void - prepare (connection&, const statement&); - - virtual void - execute (connection&, const statement&); - - virtual void - execute (connection&, const char* statement) = 0; - - virtual void - deallocate (connection&, const statement&); - - private: - // Allow these classes to convert mssql::tracer to odb::tracer. - // - friend class database; - friend class connection; - friend class transaction; - - virtual void - prepare (odb::connection&, const odb::statement&); - - virtual void - execute (odb::connection&, const odb::statement&); - - virtual void - execute (odb::connection&, const char* statement); - - virtual void - deallocate (odb::connection&, const odb::statement&); - }; - } -} - -#include - -#endif // ODB_MSSQL_TRACER_HXX diff --git a/odb/mssql/traits-calls.hxx b/odb/mssql/traits-calls.hxx deleted file mode 100644 index 6b20dbd..0000000 --- a/odb/mssql/traits-calls.hxx +++ /dev/null @@ -1,190 +0,0 @@ -// file : odb/mssql/traits-calls.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_TRAITS_CALLS_HXX -#define ODB_MSSQL_TRAITS_CALLS_HXX - -#include - -#include // std::size_t - -#include -#include -#include - -#include -#include - -namespace odb -{ - namespace mssql - { - // - // object_traits_calls - // - - template ::versioned> - struct object_traits_calls; - - template - struct object_traits_calls - { - typedef object_traits_impl traits; - typedef typename traits::image_type image_type; - typedef mssql::bind bind_type; - - object_traits_calls (const schema_version_migration*) {} - - const schema_version_migration* - version () const {return 0;} - - static void - bind (bind_type* b, image_type& i, statement_kind sk) - { - traits::bind (b, i, sk); - } - - // Poly-derived version. - // - static void - bind (bind_type* b, - const bind_type* id, std::size_t id_size, - image_type& i, - statement_kind sk) - { - traits::bind (b, id, id_size, i, sk); - } - - static void - init (T& o, const image_type& i, odb::database* db) - { - traits::init (o, i, db); - } - - static bool - find_ (typename traits::statements_type& sts, - const typename traits::id_type* id) - { - return traits::find_ (sts, id); - } - - static void - load_ (typename traits::statements_type& sts, T& o, bool reload) - { - return traits::load_ (sts, o, reload); - } - }; - - template - struct object_traits_calls - { - typedef object_traits_impl traits; - typedef typename traits::image_type image_type; - typedef mssql::bind bind_type; - - object_traits_calls (const schema_version_migration* svm): svm_ (*svm) {} - - const schema_version_migration* - version () const {return &svm_;} - - void - bind (bind_type* b, image_type& i, statement_kind sk) const - { - traits::bind (b, i, sk, svm_); - } - - // Poly-derived version. - // - void - bind (bind_type* b, - const bind_type* id, std::size_t id_size, - image_type& i, - statement_kind sk) const - { - traits::bind (b, id, id_size, i, sk, svm_); - } - - void - init (T& o, const image_type& i, odb::database* db) const - { - traits::init (o, i, db, svm_); - } - - bool - find_ (typename traits::statements_type& sts, - const typename traits::id_type* id) const - { - return traits::find_ (sts, id, svm_); - } - - void - load_ (typename traits::statements_type& sts, T& o, bool reload) const - { - return traits::load_ (sts, o, reload, svm_); - } - - private: - const schema_version_migration& svm_; - }; - - // - // view_traits_calls - // - - template ::versioned> - struct view_traits_calls; - - template - struct view_traits_calls - { - typedef view_traits_impl traits; - typedef typename traits::image_type image_type; - typedef mssql::bind bind_type; - - view_traits_calls (const schema_version_migration*) {} - - static void - bind (bind_type* b, image_type& i) - { - traits::bind (b, i); - } - - static void - init (T& o, const image_type& i, odb::database* db) - { - traits::init (o, i, db); - } - }; - - template - struct view_traits_calls - { - typedef view_traits_impl traits; - typedef typename traits::image_type image_type; - typedef mssql::bind bind_type; - - view_traits_calls (const schema_version_migration* svm): svm_ (*svm) {} - - void - bind (bind_type* b, image_type& i) const - { - traits::bind (b, i, svm_); - } - - void - init (T& o, const image_type& i, odb::database* db) const - { - traits::init (o, i, db, svm_); - } - - private: - const schema_version_migration& svm_; - }; - } -} - -#include - -#endif // ODB_MSSQL_TRAITS_CALLS_HXX diff --git a/odb/mssql/traits.cxx b/odb/mssql/traits.cxx deleted file mode 100644 index 9a9d4fa..0000000 --- a/odb/mssql/traits.cxx +++ /dev/null @@ -1,616 +0,0 @@ -// file : odb/mssql/traits.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -#include - -using namespace std; - -namespace odb -{ - namespace mssql - { - // - // c_array_value_traits_base - // - void c_array_value_traits_base:: - set_value (char* const& v, - const char* b, - size_t n, - bool is_null, - size_t N) - { - if (!is_null) - { - n = n < N ? n : N; - - if (n != 0) - memcpy (v, b, n); - } - else - n = 0; - - if (n != N) // Append '\0' if there is space. - v[n] = '\0'; - } - - void c_array_value_traits_base:: - set_image (char* b, - size_t c, - size_t& n, - bool& is_null, - const char* v, - size_t N) - { - is_null = false; - - // Figure out the length. We cannot use strlen since it may - // not be 0-terminated (strnlen is not standard). - // - for (n = 0; n != N && v[n] != '\0'; ++n) ; - - if (n > c) - n = c; - - if (n != 0) - memcpy (b, v, n); - } - - // - // default_value_traits - // - void default_value_traits:: - param_callback (const void* context, - size_t*, - const void** buffer, - size_t* size, - chunk_type* chunk, - void*, - size_t) - { - const string& str (*static_cast (context)); - - *buffer = str.c_str (); - *size = str.size (); - *chunk = chunk_one; - } - - void default_value_traits:: - result_callback (void* context, - size_t* position, - void** buffer, - size_t* size, - chunk_type chunk, - size_t size_left, - void* tmp_buf, - size_t tmp_capacity) - { - string& str (*static_cast (context)); - - switch (chunk) - { - case chunk_null: - case chunk_one: - { - str.clear (); - break; - } - case chunk_first: - { - // If the total size is available, then pre-allocate the string - // and copy the data directly into its buffer in one go. While - // this kind of direct modification of the std::string buffer - // is not sanctioned by the standard, this is known to work - // with all the implementations we care to support. We just - // need to make sure the underlying buffer is not shared with - // any other instance if the implementation uses COW. - // - if (size_left != 0) - { - size_left++; // One extra for the null terminator. - - if (str.size () != size_left) - str.resize (size_left); - else - str[0] = '\0'; // Force copy in a COW implementation. - - *buffer = const_cast (str.c_str ()); - *size = size_left; - *position = 0; // Indicator. - } - else - { - // If the total size is not available, do the short string - // optimization by first returning a small temporary buffer. - // If the data fits, then we copy it over to the string and - // thus get the precise buffer allocation. If the data does - // not fit, then we resort to the exponential buffer growth. - // - *buffer = tmp_buf; - *size = tmp_capacity > 128 ? 128 : tmp_capacity; - *position = 1; // Indicator. - } - - break; - } - case chunk_next: - { - // We should only end up here if the short string optimization - // didn't work out. - // - assert (*position != 0); - - if (*position == 1) - { - // First chunk_next call. There is some data in the temp - // buffer which we need to copy over. - // - str.reserve (256); - str.assign (static_cast (tmp_buf), *size); - *position = *size; // Size of actual data in str, which got to be - // greater than 128, or we would have gotten - // chunk_last. - str.resize (256); - } - else - { - // Subsequent chunk_next call. Double the buffer and continue. - // - *position += *size; - str.resize (str.size () * 2); - } - - *buffer = const_cast (str.c_str ()) + *position; - *size = str.size () - *position; - break; - } - case chunk_last: - { - if (*position == 0) - str.resize (*size); - else if (*position == 1) - // Short string optimization worked out. There is some data - // in the temp buffer which we need to copy over. - // - str.assign (static_cast (tmp_buf), *size); - else - str.resize (*position + *size); - - break; - } - } - } - - // - // c_long_string_value_traits - // - void c_string_long_value_traits:: - param_callback (const void* context, - size_t*, - const void** buffer, - size_t* size, - chunk_type* chunk, - void*, - size_t) - { - *buffer = context; - *size = strlen (static_cast (context)); - *chunk = chunk_one; - } - - // - // c_warray_value_traits_base - // - void c_warray_value_traits_base:: - set_value (wchar_t* const& v, - const ucs2_char* b, - size_t n, - bool is_null, - size_t N) - { - if (!is_null) - { - n = n < N ? n : N; - - if (n != 0) - functions::assign (v, b, n); - } - else - n = 0; - - if (n != N) // Append '\0' if there is space. - v[n] = L'\0'; - } - - void c_warray_value_traits_base:: - set_image (ucs2_char* b, - size_t c, - size_t& n, - bool& is_null, - const wchar_t* v, - size_t N) - { - is_null = false; - - // Figure out the length. We cannot use wcslen since it may - // not be 0-terminated (wcsnlen is not standard). - // - for (n = 0; n != N && v[n] != L'\0'; ++n) ; - - if (n > c) - n = c; - - if (n != 0) - functions::assign (b, v, n); - } - - // - // wstring_long_value_traits<2> - // - void wstring_long_value_traits<2>:: - param_callback (const void* context, - size_t*, - const void** buffer, - size_t* size, - chunk_type* chunk, - void*, - size_t) - { - const wstring& str (*static_cast (context)); - - *buffer = str.c_str (); - *size = str.size () * 2; // In bytes. - *chunk = chunk_one; - } - - void wstring_long_value_traits<2>:: - result_callback (void* context, - size_t*, - void** buffer, - size_t* size, - chunk_type chunk, - size_t size_left, - void*, - size_t) - { - wstring& str (*static_cast (context)); - - switch (chunk) - { - case chunk_null: - case chunk_one: - { - str.clear (); - break; - } - case chunk_first: - { - // The Native Client ODBC driver seems to always be able to - // return the total size for national character strings. This - // makes things simple and efficient. - // - assert (size_left != 0); - - size_left /= 2; // Convert to characters. - size_left++; // One extra for the null terminator. - - if (str.size () != size_left) - str.resize (size_left); - else - str[0] = L'\0'; // Force copy in a COW implementation. - - *buffer = const_cast (str.c_str ()); - *size = size_left * 2; // In bytes. - break; - } - case chunk_next: - { - // We should never get here. - // - assert (false); - break; - } - case chunk_last: - { - str.resize (*size / 2); // Get rid of the null terminator. - break; - } - } - } - - // - // wstring_long_value_traits<4> - // -#ifndef _WIN32 - void wstring_long_value_traits<4>:: - param_callback (const void* context, - size_t* position, - const void** buffer, - size_t* size, - chunk_type* chunk, - void* tmp_buf, - size_t tmp_capacity) - { - const wstring& str (*static_cast (context)); - - // Here we cannot just return the pointer to the underlying buffer - // since the character sizes are different. Instead we copy the - // data to the temporary buffer. - // - *buffer = tmp_buf; - *size = str.size () - *position; // In UCS-2 characters. - - if (*size > tmp_capacity / 2) - { - *size = tmp_capacity / 2; - *chunk = chunk_next; - } - else - *chunk = chunk_last; - - wstring_functions<>::assign (static_cast (tmp_buf), - str.c_str () + *position, - *size); - if (*position == 0) - { - if (*chunk == chunk_last) - *chunk = chunk_one; - else - *chunk = chunk_first; - } - - *position += *size; - *size *= 2; // Convert to bytes. - } - - void wstring_long_value_traits<4>:: - result_callback (void* context, - size_t*, - void** buffer, - size_t* size, - chunk_type chunk, - size_t size_left, - void* tmp_buf, - size_t tmp_capacity) - { - wstring& str (*static_cast (context)); - - // Again, we cannot do direct buffer copy and have to use the - // temporary buffer instead. - // - switch (chunk) - { - case chunk_null: - case chunk_one: - { - str.clear (); - break; - } - case chunk_first: - { - // The Native Client ODBC driver seems to always be able to - // return the total size for national character strings. Use - // this to reserve enough space in the string. - // - assert (size_left != 0); - str.reserve (size_left / 2); - break; - } - case chunk_next: - case chunk_last: - { - // Append the data from the temporary buffer. - // - ucs2_char* p (static_cast (tmp_buf)); - str.append (p, p + *size / 2); - break; - } - } - - if (chunk == chunk_first || chunk == chunk_next) - { - *buffer = tmp_buf; - *size = tmp_capacity; - } - } -#endif // _WIN32 - - // - // c_wstring_long_value_traits<2> - // - void c_wstring_long_value_traits<2>:: - param_callback (const void* context, - size_t*, - const void** buffer, - size_t* size, - chunk_type* chunk, - void*, - size_t) - { - *buffer = context; - *size = wcslen (static_cast (context)) * 2; // In bytes. - *chunk = chunk_one; - } - - // - // c_wstring_long_value_traits<4> - // -#ifndef _WIN32 - void c_wstring_long_value_traits<4>:: - param_callback (const void* context, - size_t* position, - const void** buffer, - size_t* size, - chunk_type* chunk, - void* tmp_buf, - size_t tmp_capacity) - { - const wchar_t* str (static_cast (context)); - - // Here we cannot just return the pointer to the buffer since the - // character sizes are different. Instead we copy the data to the - // temporary buffer. - // - *buffer = tmp_buf; - *size = wcslen (str) - *position; // In UCS-2 characters. - - if (*size > tmp_capacity / 2) - { - *size = tmp_capacity / 2; - *chunk = chunk_next; - } - else - *chunk = chunk_last; - - wstring_functions<>::assign (static_cast (tmp_buf), - str + *position, - *size); - if (*position == 0) - { - if (*chunk == chunk_last) - *chunk = chunk_one; - else - *chunk = chunk_first; - } - - *position += *size; - *size *= 2; // Convert to bytes. - } -#endif // _WIN32 - - // - // default_value_traits, id_long_binary> - // - // std::vector has to be qualified for Sun CC. - // - void default_value_traits, id_long_binary>:: - param_callback (const void* context, - size_t*, - const void** buffer, - size_t* size, - chunk_type* chunk, - void*, - size_t) - { - const value_type& v (*static_cast (context)); - - *buffer = v.empty () ? 0 : &v.front (); - *size = v.size (); - *chunk = chunk_one; - } - - void default_value_traits, id_long_binary>:: - result_callback (void* context, - size_t*, - void** buffer, - size_t* size, - chunk_type chunk, - size_t size_left, - void*, - size_t) - { - value_type& v (*static_cast (context)); - - switch (chunk) - { - case chunk_null: - case chunk_one: - { - v.clear (); - break; - } - case chunk_first: - { - // The Native Client ODBC driver seems to always be able to - // return the total size. This makes things simple and - // efficient. - // - assert (size_left != 0); - - v.resize (size_left); - *buffer = &v.front (); - *size = size_left; - break; - } - case chunk_next: - { - // We should never get here. - // - assert (false); - break; - } - case chunk_last: - { - // Nothing to do here. The vector is already of the correct size - // and should contain the data. - break; - } - } - } - - // - // default_value_traits, id_long_binary> - // - // std::vector has to be qualified for Sun CC. - // - void default_value_traits, id_long_binary>:: - param_callback (const void* context, - size_t*, - const void** buffer, - size_t* size, - chunk_type* chunk, - void*, - size_t) - { - const value_type& v (*static_cast (context)); - - *buffer = v.empty () ? 0 : &v.front (); - *size = v.size (); - *chunk = chunk_one; - } - - void default_value_traits, id_long_binary>:: - result_callback (void* context, - size_t*, - void** buffer, - size_t* size, - chunk_type chunk, - size_t size_left, - void*, - size_t) - { - // The code is exactly the same as in the vector specialization. - // - value_type& v (*static_cast (context)); - - switch (chunk) - { - case chunk_null: - case chunk_one: - { - v.clear (); - break; - } - case chunk_first: - { - assert (size_left != 0); - - v.resize (size_left); - *buffer = &v.front (); - *size = size_left; - break; - } - case chunk_next: - { - assert (false); - break; - } - case chunk_last: - { - break; - } - } - } - } -} diff --git a/odb/mssql/traits.hxx b/odb/mssql/traits.hxx deleted file mode 100644 index f53e535..0000000 --- a/odb/mssql/traits.hxx +++ /dev/null @@ -1,2176 +0,0 @@ -// file : odb/mssql/traits.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_TRAITS_HXX -#define ODB_MSSQL_TRAITS_HXX - -#include - -#include // ODB_CXX11 - -#include -#include -#include // std::size_t -#include // std::memcpy, std::memset, std::strlen -#include // std::wcslen - -#ifdef ODB_CXX11 -# include -#endif - -#ifdef _WIN32 -typedef struct _GUID GUID; -#endif - -#include -#include - -#include -#include - -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - enum database_type_id - { - id_bit, - id_tinyint, - id_smallint, - id_int, - id_bigint, - - id_decimal, // DECIMAL; NUMERIC - - id_smallmoney, - id_money, - - id_float4, // REAL; FLOAT(n) with n <= 24 - id_float8, // FLOAT(n) with n > 24 - - id_string, // CHAR(n), VARCHAR(n) with n <= N - id_long_string, // CHAR(n), VARCHAR(n) with n > N; TEXT - - id_nstring, // NCHAR(n), NVARCHAR(n) with 2*n <= N - id_long_nstring, // NCHAR(n), NVARCHAR(n) with 2*n > N; NTEXT - - id_binary, // BINARY(n), VARBINARY(n) with n <= N - id_long_binary, // BINARY(n), VARBINARY(n) with n > N; IMAGE - - id_date, // DATE - id_time, // TIME - id_datetime, // DATETIME; DATETIME2; SMALLDATETIME - id_datetimeoffset, // DATETIMEOFFSET - - id_uniqueidentifier, // UNIQUEIDENTIFIER - id_rowversion // ROWVERSION; TIMESTAMP - }; - - // - // image_traits - // - - template - struct image_traits; - - template <> - struct image_traits {typedef unsigned char image_type;}; - - template <> - struct image_traits {typedef unsigned char image_type;}; - - template <> - struct image_traits {typedef short image_type;}; - - template <> - struct image_traits {typedef int image_type;}; - - template <> - struct image_traits {typedef long long image_type;}; - - template <> - struct image_traits {typedef decimal image_type;}; - - template <> - struct image_traits {typedef smallmoney image_type;}; - - template <> - struct image_traits {typedef money image_type;}; - - template <> - struct image_traits {typedef float image_type;}; - - template <> - struct image_traits {typedef double image_type;}; - - template <> - struct image_traits {typedef char* image_type;}; - - template <> - struct image_traits {typedef long_callback image_type;}; - - template <> - struct image_traits {typedef ucs2_char* image_type;}; - - template <> - struct image_traits {typedef long_callback image_type;}; - - template <> - struct image_traits {typedef char* image_type;}; - - template <> - struct image_traits {typedef long_callback image_type;}; - - template <> - struct image_traits {typedef date image_type;}; - - template <> - struct image_traits {typedef time image_type;}; - - template <> - struct image_traits {typedef datetime image_type;}; - - template <> - struct image_traits - { - typedef datetimeoffset image_type; - }; - - template <> - struct image_traits - { - typedef uniqueidentifier image_type; - }; - - // Image is an 8-byte sequence. - // - template <> - struct image_traits {typedef unsigned char* image_type;}; - - // - // value_traits - // - - template - struct wrapped_value_traits; - - template - struct default_value_traits; - - template ::r> - struct select_traits; - - template - struct select_traits - { - typedef default_value_traits type; - }; - - template - struct select_traits - { - typedef - wrapped_value_traits::null_handler> - type; - }; - - template - class value_traits: public select_traits::type - { - }; - - // The wrapped_value_traits specializations should be able to handle - // any value type which means we have to have every possible signature - // of the set_value() and set_image() functions. - // - template - struct wrapped_value_traits - { - typedef wrapper_traits wtraits; - typedef typename wtraits::unrestricted_wrapped_type wrapped_type; - - typedef W value_type; - typedef wrapped_type query_type; - typedef typename image_traits::image_type image_type; - - typedef value_traits vtraits; - - static void - set_value (W& v, const image_type& i, bool is_null) - { - vtraits::set_value (wtraits::set_ref (v), i, is_null); - } - - static void - set_image (image_type& i, bool& is_null, const W& v) - { - vtraits::set_image (i, is_null, wtraits::get_ref (v)); - } - - // string, binary. - // - static void - set_value (W& v, const char* i, std::size_t n, bool is_null) - { - vtraits::set_value (wtraits::set_ref (v), i, n, is_null); - } - - static void - set_image (char* i, - std::size_t c, - std::size_t& n, - bool& is_null, - const W& v) - { - vtraits::set_image (i, c, n, is_null, wtraits::get_ref (v)); - } - - // nstring. - // - static void - set_value (W& v, const ucs2_char* i, std::size_t n, bool is_null) - { - vtraits::set_value (wtraits::set_ref (v), i, n, is_null); - } - - static void - set_image (ucs2_char* i, - std::size_t c, - std::size_t& n, - bool& is_null, - const W& v) - { - vtraits::set_image (i, c, n, is_null, wtraits::get_ref (v)); - } - - // long_string, long_nstring, long_binary. - // - static void - set_value (W& v, result_callback_type& cb, void*& context) - { - vtraits::set_value (wtraits::set_ref (v), cb, context); - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const W& v) - { - vtraits::set_image (cb, context, is_null, wtraits::get_ref (v)); - } - - // time, datetime, datetimeoffset. - // - static void - set_image (image_type& i, unsigned short s, bool& is_null, const W& v) - { - vtraits::set_image (i, s, is_null, wtraits::get_ref (v)); - } - }; - - template - struct wrapped_value_traits - { - typedef wrapper_traits wtraits; - typedef typename wtraits::unrestricted_wrapped_type wrapped_type; - - typedef W value_type; - typedef wrapped_type query_type; - typedef typename image_traits::image_type image_type; - - typedef value_traits vtraits; - - static void - set_value (W& v, const image_type& i, bool is_null) - { - if (is_null) - wtraits::set_null (v); - else - vtraits::set_value (wtraits::set_ref (v), i, is_null); - } - - static void - set_image (image_type& i, bool& is_null, const W& v) - { - is_null = wtraits::get_null (v); - - if (!is_null) - vtraits::set_image (i, is_null, wtraits::get_ref (v)); - } - - // string, binary. - // - static void - set_value (W& v, const char* i, std::size_t n, bool is_null) - { - if (is_null) - wtraits::set_null (v); - else - vtraits::set_value (wtraits::set_ref (v), i, n, is_null); - } - - static void - set_image (char* i, - std::size_t c, - std::size_t& n, - bool& is_null, - const W& v) - { - is_null = wtraits::get_null (v); - - if (!is_null) - vtraits::set_image (i, c, n, is_null, wtraits::get_ref (v)); - } - - // nstring. - // - static void - set_value (W& v, const ucs2_char* i, std::size_t n, bool is_null) - { - if (is_null) - wtraits::set_null (v); - else - vtraits::set_value (wtraits::set_ref (v), i, n, is_null); - } - - static void - set_image (ucs2_char* i, - std::size_t c, - std::size_t& n, - bool& is_null, - const W& v) - { - is_null = wtraits::get_null (v); - - if (!is_null) - vtraits::set_image (i, c, n, is_null, wtraits::get_ref (v)); - } - - // long_string, long_nstring, long_binary. - // - static void - set_value (W& v, result_callback_type& cb, void*& context) - { - // We have to use our own callback since the NULL information - // is only available during streaming. - // - cb = &result_callback; - context = &v; - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const W& v) - { - is_null = wtraits::get_null (v); - - if (!is_null) - vtraits::set_image (cb, context, is_null, wtraits::get_ref (v)); - } - - static void - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity); - - // time, datetime, datetimeoffset. - // - static void - set_image (image_type& i, unsigned short s, bool& is_null, const W& v) - { - is_null = wtraits::get_null (v); - - if (!is_null) - vtraits::set_image (i, s, is_null, wtraits::get_ref (v)); - } - }; - - template - struct default_value_traits - { - typedef T value_type; - typedef T query_type; - typedef typename image_traits::image_type image_type; - - static void - set_value (T& v, const image_type& i, bool is_null) - { - if (!is_null) - v = T (i); - else - v = T (); - } - - static void - set_image (image_type& i, bool& is_null, T v) - { - is_null = false; - i = image_type (v); - } - }; - - // smallmoney as float/double. - // - template - struct smallmoney_float_value_traits - { - typedef T value_type; - typedef T query_type; - typedef smallmoney image_type; - - static void - set_value (T& v, const smallmoney& i, bool is_null) - { - if (!is_null) - v = T (i.value / 10000) + T (i.value % 10000) / 10000; - else - v = T (); - } - - static void - set_image (smallmoney& i, bool& is_null, T v) - { - is_null = false; - i.value = static_cast (v) * 10000 + - static_cast (v * 10000) % 10000; - } - }; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits: - smallmoney_float_value_traits - { - }; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits: - smallmoney_float_value_traits - { - }; - - // smallmoney as integer. - // - template - struct default_value_traits - { - typedef T value_type; - typedef T query_type; - typedef smallmoney image_type; - - static void - set_value (T& v, const smallmoney& i, bool is_null) - { - if (!is_null) - v = static_cast (i.value); - else - v = T (); - } - - static void - set_image (smallmoney& i, bool& is_null, T v) - { - is_null = false; - i.value = static_cast (v); - } - }; - - // money as float/double. - // - template - struct money_float_value_traits - { - typedef T value_type; - typedef T query_type; - typedef money image_type; - - static void - set_value (T& v, const money& i, bool is_null) - { - if (!is_null) - { - long long iv ((static_cast (i.high) << 32) | i.low); - v = T (iv / 10000) + T (iv % 10000) / 10000; - } - else - v = T (); - } - - static void - set_image (money& i, bool& is_null, T v) - { - is_null = false; - long long iv (static_cast (v) * 10000 + - static_cast (v * 10000) % 10000); - i.high = static_cast (iv >> 32); - i.low = static_cast (iv); - } - }; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits: - money_float_value_traits - { - }; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits: - money_float_value_traits - { - }; - - // money as integer. - // - template - struct default_value_traits - { - typedef T value_type; - typedef T query_type; - typedef money image_type; - - static void - set_value (T& v, const money& i, bool is_null) - { - if (!is_null) - { - long long iv ((static_cast (i.high) << 32) | i.low); - v = static_cast (iv); - } - else - v = T (); - } - - static void - set_image (money& i, bool& is_null, T v) - { - is_null = false; - long long iv (static_cast (v)); - i.high = static_cast (iv >> 32); - i.low = static_cast (iv); - } - }; - - // std::string specialization for string. - // - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits - { - typedef std::string value_type; - typedef std::string query_type; - typedef char* image_type; - - static void - set_value (std::string& v, - const char* b, - std::size_t n, - bool is_null) - { - if (!is_null) - v.assign (b, n); - else - v.erase (); - } - - static void - set_image (char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const std::string& v) - { - is_null = false; - n = v.size (); - - if (n > c) - n = c; - - if (n != 0) - std::memcpy (b, v.c_str (), n); - } - }; - - // char*/const char* specialization for string. - // - // Specialization for const char* which only supports initialization - // of an image from the value but not the other way around. This way - // we can pass such values to the queries. - // - class LIBODB_MSSQL_EXPORT c_string_value_traits - { - public: - typedef const char* value_type; - typedef char* image_type; - - static void - set_image (char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const char* v) - { - is_null = false; - n = std::strlen (v); - - if (n > c) - n = c; - - if (n != 0) - std::memcpy (b, v, n); - } - }; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits: - c_string_value_traits {}; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits: - c_string_value_traits {}; - - // char[N] specialization. - // - struct LIBODB_MSSQL_EXPORT c_array_value_traits_base - { - static void - set_value (char* const& v, - const char* b, - std::size_t n, - bool is_null, - std::size_t N); - - static void - set_image (char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const char* v, - std::size_t N); - }; - - template - struct default_value_traits - { - typedef char* value_type; - typedef char query_type[N]; - typedef details::buffer image_type; - - static void - set_value (char* const& v, - const char* b, - std::size_t n, - bool is_null) - { - c_array_value_traits_base::set_value (v, b, n, is_null, N); - } - - static void - set_image (char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const char* v) - { - c_array_value_traits_base::set_image (b, c, n, is_null, v, N); - } - }; - - // std::array (string) specialization. - // -#ifdef ODB_CXX11 - template - struct default_value_traits, id_string> - { - typedef std::array value_type; - typedef std::array query_type; - typedef details::buffer image_type; - - static void - set_value (value_type& v, - const char* b, - std::size_t n, - bool is_null) - { - c_array_value_traits_base::set_value (v.data (), b, n, is_null, N); - } - - static void - set_image (char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const value_type& v) - { - c_array_value_traits_base::set_image (b, c, n, is_null, v.data (), N); - } - }; -#endif - - // char specialization. - // - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits - { - typedef char value_type; - typedef char query_type; - typedef details::buffer image_type; - - static void - set_value (char& v, - const char* b, - std::size_t n, - bool is_null) - { - c_array_value_traits_base::set_value (&v, b, n, is_null, 1); - } - - static void - set_image (char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - char v) - { - c_array_value_traits_base::set_image (b, c, n, is_null, &v, 1); - } - }; - - // std::string specialization for long_string. - // - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits - { - typedef std::string value_type; - typedef std::string query_type; - typedef long_callback image_type; - - static void - set_value (std::string& v, - result_callback_type& cb, - void*& context) - { - cb = &result_callback; - context = &v; - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const std::string& v) - { - is_null = false; - cb = ¶m_callback; - context = &v; - } - - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - - static void - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity); - }; - - // char*/const char* specialization for long_string. - // - class LIBODB_MSSQL_EXPORT c_string_long_value_traits - { - public: - typedef const char* value_type; - typedef long_callback image_type; - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const char* v) - { - is_null = false; - cb = ¶m_callback; - context = v; - } - - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - }; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits< - char*, id_long_string>: c_string_long_value_traits {}; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits< - const char*, id_long_string>: c_string_long_value_traits {}; - - // char[N] specialization for long_string. - // - template - struct c_array_long_value_traits_base - { - static void - set_value (char* const& v, - result_callback_type& cb, - void*& context) - { - cb = &result_callback; - context = v; - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const char* v) - { - is_null = false; - cb = ¶m_callback; - context = v; - } - - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - - static void - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity); - }; - - template - struct default_value_traits - { - typedef char* value_type; - typedef char query_type[N]; - typedef long_callback image_type; - - static void - set_value (char* const& v, - result_callback_type& cb, - void*& context) - { - c_array_long_value_traits_base::set_value (v, cb, context); - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const char* v) - { - c_array_long_value_traits_base::set_image (cb, context, is_null, v); - } - }; - - // std::array (long_string) specialization. - // -#ifdef ODB_CXX11 - template - struct default_value_traits, id_long_string> - { - typedef std::array value_type; - typedef std::array query_type; - typedef long_callback image_type; - - static void - set_value (value_type& v, - result_callback_type& cb, - void*& context) - { - c_array_long_value_traits_base::set_value (v.data (), cb, context); - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const value_type& v) - { - c_array_long_value_traits_base::set_image ( - cb, context, is_null, v.data ()); - } - }; -#endif - - // std::wstring specialization for nstring. - // - template - struct wstring_functions - { - static void - assign (std::wstring& s, const ucs2_char* b, std::size_t n) - { - s.assign (b, b + n); - } - - static void - assign (ucs2_char* b, const wchar_t* s, std::size_t n) - { - for (std::size_t i (0); i < n; ++i) - b[i] = static_cast (s[i]); - } - - // Even though this is not used when ucs2_char == wchar_t, the - // compiler will still compile the signatures and complain. - // -#ifndef _WIN32 - static void - assign (wchar_t* s, const ucs2_char* b, std::size_t n) - { - for (std::size_t i (0); i < n; ++i) - s[i] = static_cast (b[i]); - } -#endif - }; - - template <> - struct LIBODB_MSSQL_EXPORT wstring_functions - { - static void - assign (std::wstring& s, const ucs2_char* b, std::size_t n) - { - s.assign (reinterpret_cast (b), n); - } - - static void - assign (ucs2_char* b, const wchar_t* s, std::size_t n) - { - std::memcpy (b, s, n * sizeof (ucs2_char)); - } - - // On Windows ucs2_char is wchar_t which makes this function - // the same as the one above. - // -#ifndef _WIN32 - static void - assign (wchar_t* s, const ucs2_char* b, std::size_t n) - { - std::memcpy (s, b, n * sizeof (ucs2_char)); - } -#endif - }; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits - { - typedef std::wstring value_type; - typedef std::wstring query_type; - typedef ucs2_char* image_type; - - typedef wstring_functions<> functions; - - static void - set_value (std::wstring& v, - const ucs2_char* b, - std::size_t n, - bool is_null) - { - if (!is_null) - functions::assign (v, b, n); - else - v.erase (); - } - - static void - set_image (ucs2_char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const std::wstring& v) - { - is_null = false; - n = v.size (); - - if (n > c) - n = c; - - if (n != 0) - functions::assign (b, v.c_str (), n); - } - }; - - // wchar_t*/const wchar_t* specialization for nstring. - // - class LIBODB_MSSQL_EXPORT c_wstring_value_traits - { - public: - typedef const wchar_t* value_type; - typedef ucs2_char* image_type; - - typedef wstring_functions<> functions; - - static void - set_image (ucs2_char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const wchar_t* v) - { - is_null = false; - n = std::wcslen (v); - - if (n > c) - n = c; - - if (n != 0) - functions::assign (b, v, n); - } - }; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits: - c_wstring_value_traits {}; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits< - const wchar_t*, id_nstring>: c_wstring_value_traits {}; - - // wchar_t[N] specialization. - // - struct LIBODB_MSSQL_EXPORT c_warray_value_traits_base - { - typedef wstring_functions<> functions; - - static void - set_value (wchar_t* const& v, - const ucs2_char* b, - std::size_t n, - bool is_null, - std::size_t N); - - static void - set_image (ucs2_char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const wchar_t* v, - std::size_t N); - }; - - template - struct default_value_traits - { - typedef wchar_t* value_type; - typedef wchar_t query_type[N]; - typedef details::buffer image_type; - - static void - set_value (wchar_t* const& v, - const ucs2_char* b, - std::size_t n, - bool is_null) - { - c_warray_value_traits_base::set_value (v, b, n, is_null, N); - } - - static void - set_image (ucs2_char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const wchar_t* v) - { - c_warray_value_traits_base::set_image (b, c, n, is_null, v, N); - } - }; - - // std::array (string) specialization. - // -#ifdef ODB_CXX11 - template - struct default_value_traits, id_nstring> - { - typedef std::array value_type; - typedef std::array query_type; - typedef details::buffer image_type; - - static void - set_value (value_type& v, - const ucs2_char* b, - std::size_t n, - bool is_null) - { - c_warray_value_traits_base::set_value (v.data (), b, n, is_null, N); - } - - static void - set_image (ucs2_char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const value_type& v) - { - c_warray_value_traits_base::set_image (b, c, n, is_null, v.data (), N); - } - }; -#endif - - // wchar_t specialization. - // - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits - { - typedef wchar_t value_type; - typedef wchar_t query_type; - typedef details::buffer image_type; - - static void - set_value (wchar_t& v, - const ucs2_char* b, - std::size_t n, - bool is_null) - { - c_warray_value_traits_base::set_value (&v, b, n, is_null, 1); - } - - static void - set_image (ucs2_char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - wchar_t v) - { - c_warray_value_traits_base::set_image (b, c, n, is_null, &v, 1); - } - }; - - // std::wstring specialization for long_nstring. - // - template - struct wstring_long_value_traits; - - template <> - struct LIBODB_MSSQL_EXPORT wstring_long_value_traits<2> - { - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - - static void - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity); - }; - -#ifndef _WIN32 - template <> - struct LIBODB_MSSQL_EXPORT wstring_long_value_traits<4> - { - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - - static void - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity); - }; -#endif - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits - { - typedef std::wstring value_type; - typedef std::wstring query_type; - typedef long_callback image_type; - - static void - set_value (std::wstring& v, - result_callback_type& cb, - void*& context) - { - cb = &wstring_long_value_traits<>::result_callback; - context = &v; - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const std::wstring& v) - { - is_null = false; - cb = &wstring_long_value_traits<>::param_callback; - context = &v; - } - }; - - // wchar_t*/const wchar_t* specialization for long_nstring. - // - template - struct c_wstring_long_value_traits; - - template <> - struct LIBODB_MSSQL_EXPORT c_wstring_long_value_traits<2> - { - typedef const wchar_t* value_type; - typedef long_callback image_type; - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const wchar_t* v) - { - is_null = false; - cb = ¶m_callback; - context = v; - } - - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - }; - -#ifndef _WIN32 - template <> - struct LIBODB_MSSQL_EXPORT c_wstring_long_value_traits<4> - { - typedef const wchar_t* value_type; - typedef long_callback image_type; - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const wchar_t* v) - { - is_null = false; - cb = ¶m_callback; - context = v; - } - - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - }; -#endif - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits< - wchar_t*, id_long_nstring>: c_wstring_long_value_traits<> {}; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits< - const wchar_t*, id_long_nstring>: c_wstring_long_value_traits<> {}; - - // char[N] specialization for long_nstring. - // - template - struct c_warray_long_value_traits_base; - - template - struct c_warray_long_value_traits_base - { - static void - set_value (wchar_t* const& v, - result_callback_type& cb, - void*& context) - { - cb = &result_callback; - context = v; - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const wchar_t* v) - { - is_null = false; - cb = ¶m_callback; - context = v; - } - - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - - static void - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity); - }; - -#ifndef _WIN32 - template - struct c_warray_long_value_traits_base - { - static void - set_value (wchar_t* const& v, - result_callback_type& cb, - void*& context) - { - cb = &result_callback; - context = v; - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const wchar_t* v) - { - is_null = false; - cb = ¶m_callback; - context = v; - } - - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - - static void - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity); - }; -#endif - - template - struct default_value_traits - { - typedef wchar_t* value_type; - typedef wchar_t query_type[N]; - typedef long_callback image_type; - - static void - set_value (wchar_t* const& v, - result_callback_type& cb, - void*& context) - { - c_warray_long_value_traits_base::set_value (v, cb, context); - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const wchar_t* v) - { - c_warray_long_value_traits_base::set_image ( - cb, context, is_null, v); - } - }; - - // std::array (long_nstring) specialization. - // -#ifdef ODB_CXX11 - template - struct default_value_traits, id_long_nstring> - { - typedef std::array value_type; - typedef std::array query_type; - typedef long_callback image_type; - - static void - set_value (value_type& v, - result_callback_type& cb, - void*& context) - { - c_warray_long_value_traits_base::set_value ( - v.data (), cb, context); - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const value_type& v) - { - c_warray_long_value_traits_base::set_image ( - cb, context, is_null, v.data ()); - } - }; -#endif - - // std::vector (buffer) specialization for binary. - // - template - struct vector_binary_value_traits - { - typedef std::vector value_type; - typedef std::vector query_type; - typedef char* image_type; - - static void - set_value (value_type& v, const char* b, std::size_t n, bool is_null) - { - if (!is_null) - { - const C* cb (reinterpret_cast (b)); - v.assign (cb, cb + n); - } - else - v.clear (); - } - - static void - set_image (char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const value_type& v) - { - is_null = false; - n = v.size (); - - if (n > c) - n = c; - - // std::vector::data() may not be available in older compilers. - // - if (n != 0) - std::memcpy (b, &v.front (), n); - } - }; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits, - id_binary>: - vector_binary_value_traits - { - }; - - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits, - id_binary>: - vector_binary_value_traits - { - }; - - // C array (buffer) specialization for binary. - // - template - struct c_array_binary_value_traits - { - typedef C* value_type; - typedef C query_type[N]; - typedef char* image_type; - - static void - set_value (C* const& v, const char* b, std::size_t n, bool is_null) - { - if (!is_null) - std::memcpy (v, b, n < N ? n : N); - else - std::memset (v, 0, N); - } - - static void - set_image (char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const C* v) - { - is_null = false; - n = c > N ? N : c; - std::memcpy (b, v, n); - } - }; - - template - struct default_value_traits: - c_array_binary_value_traits - { - }; - - template - struct default_value_traits: - c_array_binary_value_traits - { - }; - -#ifdef ODB_CXX11 - // std::array (buffer) specialization for binary. - // - template - struct array_binary_value_traits - { - typedef std::array value_type; - typedef value_type query_type; - typedef char* image_type; - - static void - set_value (value_type& v, const char* b, std::size_t n, bool is_null) - { - if (!is_null) - std::memcpy (v.data (), b, n < N ? n : N); - else - std::memset (v.data (), 0, N); - } - - static void - set_image (char* b, - std::size_t c, - std::size_t& n, - bool& is_null, - const value_type& v) - { - is_null = false; - n = c > N ? N : c; - std::memcpy (b, v.data (), n); - } - }; - - template - struct default_value_traits, id_binary>: - array_binary_value_traits - { - }; - - template - struct default_value_traits, id_binary>: - array_binary_value_traits - { - }; -#endif - - // std::vector (buffer) specialization for long_binary. - // - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits, - id_long_binary> - { - typedef std::vector value_type; - typedef std::vector query_type; - typedef long_callback image_type; - - static void - set_value (value_type& v, - result_callback_type& cb, - void*& context) - { - cb = &result_callback; - context = &v; - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const value_type& v) - { - is_null = false; - cb = ¶m_callback; - context = &v; - } - - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - - static void - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity); - }; - - // std::vector (buffer) specialization for long_binary. - // - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits, - id_long_binary> - { - typedef std::vector value_type; - typedef std::vector query_type; - typedef long_callback image_type; - - static void - set_value (value_type& v, - result_callback_type& cb, - void*& context) - { - cb = &result_callback; - context = &v; - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const value_type& v) - { - is_null = false; - cb = ¶m_callback; - context = &v; - } - - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - - static void - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity); - }; - - // C array (buffer) specialization for long_binary. - // - template - struct c_array_long_binary_value_traits - { - static void - set_value (C* const& v, - result_callback_type& cb, - void*& context) - { - cb = &result_callback; - context = v; - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const C* v) - { - is_null = false; - cb = ¶m_callback; - context = v; - } - - static void - param_callback (const void* context, - std::size_t* position, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buffer, - std::size_t tmp_capacity); - - static void - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity); - }; - - template - struct default_value_traits: - c_array_long_binary_value_traits - { - typedef char* value_type; - typedef char query_type[N]; - typedef long_callback image_type; - }; - - template - struct default_value_traits: - c_array_long_binary_value_traits - { - typedef unsigned char* value_type; - typedef unsigned char query_type[N]; - typedef long_callback image_type; - }; - -#ifdef ODB_CXX11 - // std::array (buffer) specialization for long_binary. - // - template - struct default_value_traits, id_long_binary> - { - typedef std::array value_type; - typedef value_type query_type; - typedef long_callback image_type; - - static void - set_value (value_type& v, - result_callback_type& cb, - void*& context) - { - c_array_long_binary_value_traits::set_value ( - v.data (), cb, context); - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const value_type& v) - { - c_array_long_binary_value_traits::set_image ( - cb, context, is_null, v.data ()); - } - }; - - template - struct default_value_traits, id_long_binary> - { - typedef std::array value_type; - typedef value_type query_type; - typedef long_callback image_type; - - static void - set_value (value_type& v, - result_callback_type& cb, - void*& context) - { - c_array_long_binary_value_traits::set_value ( - v.data (), cb, context); - } - - static void - set_image (param_callback_type& cb, - const void*& context, - bool& is_null, - const value_type& v) - { - c_array_long_binary_value_traits::set_image ( - cb, context, is_null, v.data ()); - } - }; -#endif - - // GUID specialization for uniqueidentifier. - // -#ifdef _WIN32 - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits - { - typedef GUID value_type; - typedef GUID query_type; - typedef uniqueidentifier image_type; - - static void - set_value (GUID& v, const uniqueidentifier& i, bool is_null) - { - if (!is_null) - std::memcpy (&v, &i, 16); - else - std::memset (&v, 0, 16); - } - - static void - set_image (uniqueidentifier& i, bool& is_null, const GUID& v) - { - is_null = false; - std::memcpy (&i, &v, 16); - } - }; -#endif - - // char[16] specialization for uniqueidentifier. - // - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits - { - typedef char* value_type; - typedef char query_type[16]; - typedef uniqueidentifier image_type; - - static void - set_value (char* const& v, const uniqueidentifier& i, bool is_null) - { - if (!is_null) - std::memcpy (v, &i, 16); - else - std::memset (v, 0, 16); - } - - static void - set_image (uniqueidentifier& i, bool& is_null, const char* v) - { - is_null = false; - std::memcpy (&i, v, 16); - } - }; - - // unsigned long long specialization for rowversion. - // - template <> - struct LIBODB_MSSQL_EXPORT default_value_traits - { - typedef unsigned long long value_type; - typedef unsigned long long query_type; - typedef unsigned char* image_type; - - static void - set_value (unsigned long long& v, const unsigned char* i, bool is_null) - { - if (!is_null) - { - // The value is in the big-endian format. - // - unsigned char* p (reinterpret_cast (&v)); - p[0] = i[7]; - p[1] = i[6]; - p[2] = i[5]; - p[3] = i[4]; - p[4] = i[3]; - p[5] = i[2]; - p[6] = i[1]; - p[7] = i[0]; - } - else - v = 0; - } - - static void - set_image (unsigned char* i, bool& is_null, unsigned long long v) - { - is_null = false; - - // The value is in the big-endian format. - // - const unsigned char* p (reinterpret_cast (&v)); - i[0] = p[7]; - i[1] = p[6]; - i[2] = p[5]; - i[3] = p[4]; - i[4] = p[3]; - i[5] = p[2]; - i[6] = p[1]; - i[7] = p[0]; - } - }; - - // - // type_traits - // - - template - struct default_type_traits; - - template - class type_traits: public default_type_traits - { - }; - - // Integral types. - // - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_bit; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_tinyint; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_tinyint; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_smallint; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_smallint; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_int; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_int; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_bigint; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_bigint; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_bigint; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_bigint; - }; - - // Float types. - // - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_float4; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_float8; - }; - - // String types. - // - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_long_string; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_long_string; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_long_string; - }; - - template - struct default_type_traits - { - // Use short string by default to minimize code bloat. Can - // always be overridden with _val()/_ref(). - // - static const database_type_id db_type_id = id_string; - }; - -#ifdef ODB_CXX11 - template - struct default_type_traits > - { - // Ditto. - // - static const database_type_id db_type_id = id_string; - }; -#endif - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_string; - }; - - // Wide string types. - // - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_long_nstring; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_long_nstring; - }; - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_long_nstring; - }; - - template - struct default_type_traits - { - // Use short string by default to minimize code bloat. Can - // always be overridden with _val()/_ref(). - // - static const database_type_id db_type_id = id_nstring; - }; - -#ifdef ODB_CXX11 - template - struct default_type_traits > - { - // Ditto. - // - static const database_type_id db_type_id = id_nstring; - }; -#endif - - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_nstring; - }; - - // Binary types. - // - template - struct default_type_traits - { - static const database_type_id db_type_id = id_long_binary; - }; - - template <> - struct default_type_traits > - { - static const database_type_id db_type_id = id_long_binary; - }; - - template <> - struct default_type_traits > - { - static const database_type_id db_type_id = id_long_binary; - }; - -#ifdef ODB_CXX11 - template - struct default_type_traits > - { - static const database_type_id db_type_id = id_long_binary; - }; -#endif - - // GUID. - // -#ifdef _WIN32 - template <> - struct default_type_traits - { - static const database_type_id db_type_id = id_uniqueidentifier; - }; -#endif - } -} - -#include - -#include - -#endif // ODB_MSSQL_TRAITS_HXX diff --git a/odb/mssql/traits.txx b/odb/mssql/traits.txx deleted file mode 100644 index 683054c..0000000 --- a/odb/mssql/traits.txx +++ /dev/null @@ -1,399 +0,0 @@ -// file : odb/mssql/traits.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -namespace odb -{ - namespace mssql - { - // - // wrapped_value_traits - // - template - void wrapped_value_traits:: - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buffer, - std::size_t tmp_capacity) - { - W& v (*static_cast (context)); - - if (chunk == chunk_null) - wtraits::set_null (v); - else - { - long_callback& c (*static_cast (*buffer)); - - // Redirect all further calls. - // - vtraits::set_value (wtraits::set_ref (v), - c.callback.result, - c.context.result); - - // Forward this call. - // - c.callback.result ( - c.context.result, - position, - buffer, - size, - chunk, - size_left, - tmp_buffer, - tmp_capacity); - } - } - - // - // c_array_long_value_traits_base - // - template - void c_array_long_value_traits_base:: - param_callback (const void* context, - std::size_t*, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void*, - std::size_t) - { - // Figure out the length. We cannot use strlen since it may - // not be 0-terminated (strnlen is not standard). - // - size_t n (0); - for (; n != N && static_cast (context)[n] != '\0'; ++n); - - *buffer = context; - *size = n; - *chunk = chunk_one; - } - - template - void c_array_long_value_traits_base:: - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t, - void* tmp_buf, - std::size_t tmp_capacity) - { - char* p (static_cast (context)); - - switch (chunk) - { - case chunk_null: - case chunk_one: - { - *p = '\0'; - break; - } - case chunk_first: - { - *buffer = p; - *size = N; - break; - } - case chunk_next: - { - // ODBC insists on appending '\0' to each chunk it returns. - // As a result, we can get here if the last character did not - // fit into our buffer. There could also be more data but since - // there is no way to stop until we read all the data, dump - // the remainder into the temporary buffer. - // - - // Use position to indicate whether this is the first "next - // chunk". - // - if (*position == 0) - *position = 1; - else if (*position == 1) - { - p[N - 1] = *static_cast (tmp_buf); - *position = 2; - } - - *buffer = tmp_buf; - *size = tmp_capacity; - break; - } - case chunk_last: - { - if (*position == 0) - { - if (*size < N) // Append '\0' if there is space. - p[*size] = '\0'; - } - else if (*position == 1) - p[N - 1] = *static_cast (tmp_buf); - - break; - } - } - } - - // - // c_warray_long_value_traits_base<2> - // - template - void c_warray_long_value_traits_base:: - param_callback (const void* context, - std::size_t*, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void*, - std::size_t) - { - // Figure out the length. We cannot use wcslen since it may - // not be 0-terminated (wcsnlen is not standard). - // - size_t n (0); - for (; n != N && static_cast (context)[n] != L'\0'; ++n); - - *buffer = context; - *size = n * 2; // In bytes. - *chunk = chunk_one; - } - - template - void c_warray_long_value_traits_base:: - result_callback (void* context, - std::size_t* position, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t, - void* tmp_buf, - std::size_t tmp_capacity) - { - wchar_t* p (static_cast (context)); - - switch (chunk) - { - case chunk_null: - case chunk_one: - { - *p = L'\0'; - break; - } - case chunk_first: - { - *buffer = p; - *size = N * 2; // In bytes - break; - } - case chunk_next: - { - // ODBC insists on appending '\0' to each chunk it returns. - // As a result, we can get here if the last character did not - // fit into our buffer. There could also be more data but since - // there is no way to stop until we read all the data, dump - // the remainder into the temporary buffer. - // - - // Use position to indicate whether this is the first "next - // chunk". - // - if (*position == 0) - *position = 1; - else if (*position == 1) - { - p[N - 1] = *static_cast (tmp_buf); - *position = 2; - } - - *buffer = tmp_buf; - *size = tmp_capacity; - break; - } - case chunk_last: - { - if (*position == 0) - { - size_t n (*size / 2); // In wide characters. - if (n < N) // Append '\0' if there is space. - p[n] = L'\0'; - } - else if (*position == 1) - p[N - 1] = *static_cast (tmp_buf); - - break; - } - } - } - -#ifndef _WIN32 - // - // c_warray_long_value_traits_base<4> - // - template - void c_warray_long_value_traits_base:: - param_callback (const void* context, - std::size_t* pos, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void* tmp_buf, - std::size_t tmp_capacity) - { - // Here we cannot just return the pointer to the underlying buffer - // since the character sizes are different. Instead we copy the - // data to the temporary buffer. - // - ucs2_char* d (static_cast (tmp_buf)); - const wchar_t* s (static_cast (context) + *pos); - - size_t n (0); - tmp_capacity /= 2; // In UCS-2 character. - for (const wchar_t* e (s + N); - s != e && *s != L'\0' && n != tmp_capacity; - ++n, ++s) - d[n] = static_cast (*s); - - *buffer = d; - *size = n * 2; // In bytes. - *chunk = (n != tmp_capacity ? chunk_last : chunk_next); - - if (*pos == 0) - { - if (*chunk == chunk_last) - *chunk = chunk_one; - else - *chunk = chunk_first; - } - - *pos += n; - } - - template - void c_warray_long_value_traits_base:: - result_callback (void* context, - std::size_t* pos, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t, - void* tmp_buf, - std::size_t tmp_capacity) - { - wchar_t* d (static_cast (context)); - const ucs2_char* s (static_cast (tmp_buf)); - - // Again, we cannot do direct buffer copy and have to use the - // temporary buffer instead. - // - switch (chunk) - { - case chunk_null: - case chunk_one: - { - *d = L'\0'; - break; - } - case chunk_first: - { - break; - } - case chunk_next: - case chunk_last: - { - // Append the data from the temporary buffer. - // - if (*pos < N) - { - *size /= 2; // In UCS-2 characters. - size_t n (N - *pos); - n = *size < n ? *size : n; - - wstring_functions<>::assign (d + *pos, s, n); - *pos += n; - - if (*pos < N) // Append '\0' if there is space. - d[*pos] = L'\0'; - } - - break; - } - } - - if (chunk == chunk_first || chunk == chunk_next) - { - *buffer = tmp_buf; - *size = tmp_capacity; - } - } -#endif - - // - // c_array_long_binary_value_traits - // - template - void c_array_long_binary_value_traits:: - param_callback (const void* context, - std::size_t*, - const void** buffer, - std::size_t* size, - chunk_type* chunk, - void*, - std::size_t) - { - *buffer = context; - *size = N; - *chunk = chunk_one; - } - - template - void c_array_long_binary_value_traits:: - result_callback (void* context, - std::size_t*, - void** buffer, - std::size_t* size, - chunk_type chunk, - std::size_t size_left, - void* tmp_buf, - std::size_t tmp_capacity) - { - // The code is similar to the vector specialization. - // - switch (chunk) - { - case chunk_null: - case chunk_one: - { - std::memset (context, 0, N); - break; - } - case chunk_first: - { - assert (size_left != 0); - - *buffer = context; - *size = size_left < N ? size_left : N; - break; - } - case chunk_next: - { - // We can get here if total size is greater than N. There is - // no way to stop until we read all the data, so dump the - // remainder into the temporary buffer. - // - *buffer = tmp_buf; - *size = tmp_capacity; - break; - } - case chunk_last: - { - break; - } - } - } - } -} diff --git a/odb/mssql/transaction-impl.cxx b/odb/mssql/transaction-impl.cxx deleted file mode 100644 index a44e83f..0000000 --- a/odb/mssql/transaction-impl.cxx +++ /dev/null @@ -1,103 +0,0 @@ -// file : odb/mssql/transaction-impl.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -#include -#include -#include -#include -#include - -namespace odb -{ - namespace mssql - { - transaction_impl:: - transaction_impl (database_type& db) - : odb::transaction_impl (db) - { - } - - transaction_impl:: - transaction_impl (connection_ptr c) - : odb::transaction_impl (c->database (), *c), connection_ (c) - { - } - - transaction_impl:: - ~transaction_impl () - { - } - - void transaction_impl:: - start () - { - // Grab a connection if we don't already have one. - // - if (connection_ == 0) - { - connection_ = static_cast (database_).connection (); - odb::transaction_impl::connection_ = connection_.get (); - } - - { - odb::tracer* t; - if ((t = connection_->tracer ()) || (t = database_.tracer ())) - t->execute (*connection_, "BEGIN"); - } - - // In ODBC a transaction is started automatically before the first - // statement is executed. - // - } - - void transaction_impl:: - commit () - { - // Invalidate query results. - // - connection_->invalidate_results (); - - { - odb::tracer* t; - if ((t = connection_->tracer ()) || (t = database_.tracer ())) - t->execute (*connection_, "COMMIT"); - } - - SQLRETURN r ( - SQLEndTran (SQL_HANDLE_DBC, connection_->handle (), SQL_COMMIT)); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, *connection_, true); - - // Release the connection. - // - connection_.reset (); - } - - void transaction_impl:: - rollback () - { - // Invalidate query results. - // - connection_->invalidate_results (); - - { - odb::tracer* t; - if ((t = connection_->tracer ()) || (t = database_.tracer ())) - t->execute (*connection_, "ROLLBACK"); - } - - SQLRETURN r ( - SQLEndTran (SQL_HANDLE_DBC, connection_->handle (), SQL_ROLLBACK)); - - if (!SQL_SUCCEEDED (r)) - translate_error (r, *connection_, true); - - // Release the connection. - // - connection_.reset (); - } - } -} diff --git a/odb/mssql/transaction-impl.hxx b/odb/mssql/transaction-impl.hxx deleted file mode 100644 index f7189f2..0000000 --- a/odb/mssql/transaction-impl.hxx +++ /dev/null @@ -1,49 +0,0 @@ -// file : odb/mssql/transaction-impl.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_TRANSACTION_IMPL_HXX -#define ODB_MSSQL_TRANSACTION_IMPL_HXX - -#include - -#include - -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - class LIBODB_MSSQL_EXPORT transaction_impl: public odb::transaction_impl - { - public: - typedef mssql::database database_type; - typedef mssql::connection connection_type; - - transaction_impl (database_type&); - transaction_impl (connection_ptr); - - virtual - ~transaction_impl (); - - virtual void - start (); - - virtual void - commit (); - - virtual void - rollback (); - - private: - connection_ptr connection_; - }; - } -} - -#include - -#endif // ODB_MSSQL_TRANSACTION_IMPL_HXX diff --git a/odb/mssql/transaction.cxx b/odb/mssql/transaction.cxx deleted file mode 100644 index bb51697..0000000 --- a/odb/mssql/transaction.cxx +++ /dev/null @@ -1,26 +0,0 @@ -// file : odb/mssql/transaction.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include - -#include - -namespace odb -{ - namespace mssql - { - transaction& transaction:: - current () - { - // While the impl type can be of the concrete type, the transaction - // object can be created as either odb:: or odb::mssql:: type. To - // work around that we are going to hard-cast one to the other - // relying on the fact that they have the same representation and - // no virtual functions. The former is checked in the tests. - // - odb::transaction& b (odb::transaction::current ()); - assert (dynamic_cast (&b.implementation ()) != 0); - return reinterpret_cast (b); - } - } -} diff --git a/odb/mssql/transaction.hxx b/odb/mssql/transaction.hxx deleted file mode 100644 index 8c86515..0000000 --- a/odb/mssql/transaction.hxx +++ /dev/null @@ -1,88 +0,0 @@ -// file : odb/mssql/transaction.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_TRANSACTION_HXX -#define ODB_MSSQL_TRANSACTION_HXX - -#include - -#include - -#include -#include -#include - -#include - -namespace odb -{ - namespace mssql - { - class transaction_impl; - - class LIBODB_MSSQL_EXPORT transaction: public odb::transaction - { - public: - typedef mssql::database database_type; - typedef mssql::connection connection_type; - - explicit - transaction (transaction_impl*, bool make_current = true); - - transaction (); - - // Return the database this transaction is on. - // - database_type& - database (); - - // Return the underlying database connection for this transaction. - // - connection_type& - connection (); - - connection_type& - connection (odb::database&); - - // Return current transaction or throw if there is no transaction - // in effect. - // - static transaction& - current (); - - // Set the current thread's transaction. - // - static void - current (transaction&); - - // SQL statement tracing. - // - public: - typedef mssql::tracer tracer_type; - - void - tracer (tracer_type& t) - { - odb::transaction::tracer (t); - } - - void - tracer (tracer_type* t) - { - odb::transaction::tracer (t); - } - - using odb::transaction::tracer; - - public: - transaction_impl& - implementation (); - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_TRANSACTION_HXX diff --git a/odb/mssql/transaction.ixx b/odb/mssql/transaction.ixx deleted file mode 100644 index ac819bc..0000000 --- a/odb/mssql/transaction.ixx +++ /dev/null @@ -1,57 +0,0 @@ -// file : odb/mssql/transaction.ixx -// license : ODB NCUEL; see accompanying LICENSE file - -#include -#include - -namespace odb -{ - namespace mssql - { - inline transaction:: - transaction (transaction_impl* impl, bool make_current) - : odb::transaction (impl, make_current) - { - } - - inline transaction:: - transaction () - : odb::transaction () - { - } - - inline transaction_impl& transaction:: - implementation () - { - // We can use static_cast here since we have an instance of - // mssql::transaction. - // - return static_cast ( - odb::transaction::implementation ()); - } - - inline transaction::database_type& transaction:: - database () - { - return static_cast (odb::transaction::database ()); - } - - inline transaction::connection_type& transaction:: - connection () - { - return static_cast (odb::transaction::connection ()); - } - - inline transaction::connection_type& transaction:: - connection (odb::database& db) - { - return static_cast (odb::transaction::connection (db)); - } - - inline void transaction:: - current (transaction& t) - { - odb::transaction::current (t); - } - } -} diff --git a/odb/mssql/version-build2-stub.hxx b/odb/mssql/version-build2-stub.hxx deleted file mode 100644 index 969ab3c..0000000 --- a/odb/mssql/version-build2-stub.hxx +++ /dev/null @@ -1,4 +0,0 @@ -// file : odb/mssql/version-build2-stub.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#include diff --git a/odb/mssql/version-build2.hxx b/odb/mssql/version-build2.hxx deleted file mode 100644 index e69de29..0000000 diff --git a/odb/mssql/version-build2.hxx.in b/odb/mssql/version-build2.hxx.in deleted file mode 100644 index 9f57dfe..0000000 --- a/odb/mssql/version-build2.hxx.in +++ /dev/null @@ -1,42 +0,0 @@ -// file : odb/mssql/version-build2.hxx.in -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef LIBODB_MSSQL_VERSION // Note: using the version macro itself. - -// The numeric version format is AAAAABBBBBCCCCCDDDE where: -// -// AAAAA - major version number -// BBBBB - minor version number -// CCCCC - bugfix version number -// DDD - alpha / beta (DDD + 500) version number -// E - final (0) / snapshot (1) -// -// When DDDE is not 0, 1 is subtracted from AAAAABBBBBCCCCC. For example: -// -// Version AAAAABBBBBCCCCCDDDE -// -// 0.1.0 0000000001000000000 -// 0.1.2 0000000001000020000 -// 1.2.3 0000100002000030000 -// 2.2.0-a.1 0000200001999990010 -// 3.0.0-b.2 0000299999999995020 -// 2.2.0-a.1.z 0000200001999990011 -// -#define LIBODB_MSSQL_VERSION $libodb_mssql.version.project_number$ULL -#define LIBODB_MSSQL_VERSION_STR "$libodb_mssql.version.project$" -#define LIBODB_MSSQL_VERSION_ID "$libodb_mssql.version.project_id$" - -#define LIBODB_MSSQL_VERSION_MAJOR $libodb_mssql.version.major$ -#define LIBODB_MSSQL_VERSION_MINOR $libodb_mssql.version.minor$ -#define LIBODB_MSSQL_VERSION_PATCH $libodb_mssql.version.patch$ - -#define LIBODB_MSSQL_PRE_RELEASE $libodb_mssql.version.pre_release$ - -#define LIBODB_MSSQL_SNAPSHOT $libodb_mssql.version.snapshot_sn$ULL -#define LIBODB_MSSQL_SNAPSHOT_ID "$libodb_mssql.version.snapshot_id$" - -#include - -$libodb.check(LIBODB_VERSION, LIBODB_SNAPSHOT)$ - -#endif // LIBODB_MSSQL_VERSION diff --git a/odb/mssql/version.hxx b/odb/mssql/version.hxx deleted file mode 100644 index 5b6cc56..0000000 --- a/odb/mssql/version.hxx +++ /dev/null @@ -1,48 +0,0 @@ -// file : odb/mssql/version.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifdef LIBODB_MSSQL_BUILD2 -# include -#else - -#ifndef ODB_MSSQL_VERSION_HXX -#define ODB_MSSQL_VERSION_HXX - -#include - -#include -#include - -// Version format is AABBCCDD where -// -// AA - major version number -// BB - minor version number -// CC - bugfix version number -// DD - alpha / beta (DD + 50) version number -// -// When DD is not 00, 1 is subtracted from AABBCC. For example: -// -// Version AABBCCDD -// 2.0.0 02000000 -// 2.1.0 02010000 -// 2.1.1 02010100 -// 2.2.0.a1 02019901 -// 3.0.0.b2 02999952 -// - -// Check that we have compatible ODB version. -// -#if ODB_VERSION != 20476 -# error incompatible odb interface version detected -#endif - -// libodb-mssql version: odb interface version plus the bugfix -// version. -// -#define LIBODB_MSSQL_VERSION 2049976 -#define LIBODB_MSSQL_VERSION_STR "2.5.0-b.26" - -#include - -#endif // ODB_MSSQL_VERSION_HXX -#endif // LIBODB_MSSQL_BUILD2 diff --git a/odb/mssql/view-result.hxx b/odb/mssql/view-result.hxx deleted file mode 100644 index 41e5b8e..0000000 --- a/odb/mssql/view-result.hxx +++ /dev/null @@ -1,85 +0,0 @@ -// file : odb/mssql/view-result.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_VIEW_RESULT_HXX -#define ODB_MSSQL_VIEW_RESULT_HXX - -#include - -#include // std::size_t - -#include -#include - -#include - -#include -#include // query_base, view_statements -#include -#include - -namespace odb -{ - namespace mssql - { - template - class view_result_impl: public odb::view_result_impl - { - public: - typedef odb::view_result_impl base_type; - - typedef typename base_type::view_type view_type; - typedef typename base_type::pointer_type pointer_type; - - typedef view_traits_impl view_traits; - typedef typename base_type::pointer_traits pointer_traits; - - typedef view_statements statements_type; - - virtual - ~view_result_impl (); - - view_result_impl (const query_base&, - details::shared_ptr, - statements_type&, - const schema_version_migration*); - - virtual void - load (view_type&); - - virtual void - next (); - - virtual void - cache (); - - virtual std::size_t - size (); - - virtual void - invalidate (); - - using base_type::current; - - private: - typedef mssql::change_callback change_callback_type; - - static void - change_callback (void* context); - - private: - details::shared_ptr statement_; - statements_type& statements_; - view_traits_calls tc_; - bool can_load_; - bool use_copy_; - typename view_traits::image_type* image_copy_; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_VIEW_RESULT_HXX diff --git a/odb/mssql/view-result.txx b/odb/mssql/view-result.txx deleted file mode 100644 index 7818d36..0000000 --- a/odb/mssql/view-result.txx +++ /dev/null @@ -1,153 +0,0 @@ -// file : odb/mssql/view-result.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include -#include // result_not_cached - -#include // long_data_reload -#include - -namespace odb -{ - namespace mssql - { - template - view_result_impl:: - ~view_result_impl () - { - invalidate (); - } - - template - void view_result_impl:: - invalidate () - { - change_callback_type& cc (statements_.image ().change_callback_); - - if (cc.context == this) - { - cc.callback = 0; - cc.context = 0; - } - - delete image_copy_; - image_copy_ = 0; - - if (!this->end_) - { - statement_->free_result (); - this->end_ = true; - } - - statement_.reset (); - } - - template - view_result_impl:: - view_result_impl (const query_base&, - details::shared_ptr statement, - statements_type& statements, - const schema_version_migration* svm) - : base_type (statements.connection ()), - statement_ (statement), - statements_ (statements), - tc_ (svm), - use_copy_ (false), - image_copy_ (0) - { - } - - template - void view_result_impl:: - load (view_type& view) - { - if (!can_load_) - throw long_data_reload (); - - view_traits::callback (this->db_, view, callback_event::pre_load); - - tc_.init (view, - use_copy_ ? *image_copy_ : statements_.image (), - &this->db_); - - // If we are using a copy, make sure the callback information for - // long data also comes from the copy. - // - can_load_ = !statement_->stream_result ( - use_copy_ ? &statements_.image () : 0, - use_copy_ ? image_copy_ : 0); - - view_traits::callback (this->db_, view, callback_event::post_load); - } - - template - void view_result_impl:: - next () - { - can_load_ = true; - this->current (pointer_type ()); - - typename view_traits::image_type& im (statements_.image ()); - change_callback_type& cc (im.change_callback_); - - if (cc.context == this) - { - cc.callback = 0; - cc.context = 0; - } - - use_copy_ = false; - - if (im.version != statements_.image_version ()) - { - binding& b (statements_.image_binding ()); - tc_.bind (b.bind, im); - statements_.image_version (im.version); - b.version++; - } - - if (statement_->fetch () == select_statement::no_data) - { - statement_->free_result (); - this->end_ = true; - } - else - { - cc.callback = &change_callback; - cc.context = this; - } - } - - template - void view_result_impl:: - cache () - { - } - - template - std::size_t view_result_impl:: - size () - { - throw result_not_cached (); - } - - template - void view_result_impl:: - change_callback (void* c) - { - view_result_impl* r (static_cast*> (c)); - - typename view_traits::image_type& im (r->statements_.image ()); - - if (r->image_copy_ == 0) - r->image_copy_ = new typename view_traits::image_type (im); - else - *r->image_copy_ = im; - - im.change_callback_.callback = 0; - im.change_callback_.context = 0; - - r->use_copy_ = true; - } - } -} diff --git a/odb/mssql/view-statements.hxx b/odb/mssql/view-statements.hxx deleted file mode 100644 index 1742cab..0000000 --- a/odb/mssql/view-statements.hxx +++ /dev/null @@ -1,83 +0,0 @@ -// file : odb/mssql/view-statements.hxx -// license : ODB NCUEL; see accompanying LICENSE file - -#ifndef ODB_MSSQL_VIEW_STATEMENTS_HXX -#define ODB_MSSQL_VIEW_STATEMENTS_HXX - -#include - -#include // std::size_t - -#include -#include - -#include -#include -#include -#include - -namespace odb -{ - namespace mssql - { - template - class view_statements: public statements_base - { - public: - typedef T view_type; - typedef view_traits_impl view_traits; - typedef typename view_traits::pointer_type pointer_type; - typedef typename view_traits::image_type image_type; - - public: - view_statements (connection_type&); - - virtual - ~view_statements (); - - // View image. - // - image_type& - image () - { - return image_; - } - - std::size_t - image_version () const - { - return image_version_; - } - - void - image_version (std::size_t v) - { - image_version_ = v; - } - - binding& - image_binding () - { - return image_binding_; - } - - private: - view_statements (const view_statements&); - view_statements& operator= (const view_statements&); - - private: - image_type image_; - std::size_t image_version_; - binding image_binding_; - bind image_bind_[view_traits::column_count != 0 - ? view_traits::column_count - : 1]; - }; - } -} - -#include - -#include - -#endif // ODB_MSSQL_VIEW_STATEMENTS_HXX diff --git a/odb/mssql/view-statements.txx b/odb/mssql/view-statements.txx deleted file mode 100644 index e217523..0000000 --- a/odb/mssql/view-statements.txx +++ /dev/null @@ -1,30 +0,0 @@ -// file : odb/mssql/view-statements.txx -// license : ODB NCUEL; see accompanying LICENSE file - -#include // std::memset - -namespace odb -{ - namespace mssql - { - template - view_statements:: - ~view_statements () - { - } - - template - view_statements:: - view_statements (connection_type& conn) - : statements_base (conn), - image_binding_ (image_bind_, view_traits::column_count) - { - image_.version = 0; - image_version_ = 0; - - image_binding_.change_callback = image_.change_callback (); - - std::memset (image_bind_, 0, sizeof (image_bind_)); - } - } -} diff --git a/repositories.manifest b/repositories.manifest deleted file mode 100644 index 6b2c43b..0000000 --- a/repositories.manifest +++ /dev/null @@ -1,10 +0,0 @@ -: 1 -summary: Microsoft SQL Server ODB runtime library repository - -: -role: prerequisite -location: ../libodb.git##HEAD - -: -role: prerequisite -location: https://git.codesynthesis.com/cli/cli.git##HEAD diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index e54525b..0000000 --- a/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -driver diff --git a/tests/basics/buildfile b/tests/basics/buildfile deleted file mode 100644 index ee213f5..0000000 --- a/tests/basics/buildfile +++ /dev/null @@ -1,6 +0,0 @@ -# file : tests/basics/buildfile -# license : ODB NCUEL; see accompanying LICENSE file - -import libs = libodb-mssql%lib{odb-mssql} - -exe{driver}: {hxx cxx}{*} $libs diff --git a/tests/basics/driver.cxx b/tests/basics/driver.cxx deleted file mode 100644 index 04d7231..0000000 --- a/tests/basics/driver.cxx +++ /dev/null @@ -1,37 +0,0 @@ -// file : tests/basics/driver.cxx -// license : ODB NCUEL; see accompanying LICENSE file - -// Basic test to make sure the library is usable. Functionality testing -// is done in the odb-tests package. - -#include -#include - -#include -#include -#include - -using namespace odb::mssql; - -int -main () -{ - { - std::ostringstream os; - database::print_usage (os); - assert (!os.str ().empty ()); - } - - // We can't really do much here since that would require a database. We can - // create a fake database object as long as we don't expect to get a valid - // connection. - // - database db ("john", "secret", "dummy whammy"); - - try - { - transaction t (db.begin ()); - assert (false); - } - catch (const database_exception&) {} -} diff --git a/tests/build/.gitignore b/tests/build/.gitignore deleted file mode 100644 index 4a730a3..0000000 --- a/tests/build/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -config.build -root/ -bootstrap/ diff --git a/tests/build/bootstrap.build b/tests/build/bootstrap.build deleted file mode 100644 index 895126c..0000000 --- a/tests/build/bootstrap.build +++ /dev/null @@ -1,8 +0,0 @@ -# file : tests/build/bootstrap.build -# license : ODB NCUEL; see accompanying LICENSE file - -project = # Unnamed subproject. - -using config -using dist -using test diff --git a/tests/build/root.build b/tests/build/root.build deleted file mode 100644 index bbd3781..0000000 --- a/tests/build/root.build +++ /dev/null @@ -1,23 +0,0 @@ -# file : tests/build/root.build -# license : ODB NCUEL; see accompanying LICENSE file - -cxx.std = latest - -using cxx - -hxx{*}: extension = hxx -cxx{*}: extension = cxx - -if ($cxx.target.system == 'win32-msvc') - cxx.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS - -if ($cxx.class == 'msvc') - cxx.coptions += /wd4251 /wd4275 /wd4800 - -# Every exe{} in this subproject is by default a test. -# -exe{*}: test = true - -# Specify the test target for cross-testing. -# -test.target = $cxx.target diff --git a/tests/buildfile b/tests/buildfile deleted file mode 100644 index fd73adc..0000000 --- a/tests/buildfile +++ /dev/null @@ -1,4 +0,0 @@ -# file : tests/buildfile -# license : ODB NCUEL; see accompanying LICENSE file - -./: {*/ -build/} diff --git a/version.txt b/version.txt deleted file mode 100644 index 6bc2f39..0000000 --- a/version.txt +++ /dev/null @@ -1 +0,0 @@ -2.5.0-b.26 -- cgit v1.1