diff options
138 files changed, 3079 insertions, 731 deletions
@@ -1,3 +1,5 @@ +Copyright (c) 2009-2024 Code Synthesis Tools CC. + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. diff --git a/Makefile.am b/Makefile.am index d4c93b8..2c34934 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,4 @@ # file : Makefile.am -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file SUBDIRS = __path__(dirs) @@ -1,7 +1,6 @@ #! /bin/sh # file : bootstrap -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file # diff --git a/build/bootstrap.build b/build/bootstrap.build index d752fd7..fb6b7df 100644 --- a/build/bootstrap.build +++ b/build/bootstrap.build @@ -1,5 +1,4 @@ # file : build/bootstrap.build -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file project = libodb-pgsql diff --git a/build/bootstrap.make b/build/bootstrap.make index 83a4ccb..26da3c4 100644 --- a/build/bootstrap.make +++ b/build/bootstrap.make @@ -1,5 +1,4 @@ # file : build/bootstrap.make -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file project_name := libodb-pgsql diff --git a/build/export.build b/build/export.build index 01d806d..80aba23 100644 --- a/build/export.build +++ b/build/export.build @@ -1,5 +1,4 @@ # file : build/export.build -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file $out_root/ diff --git a/build/export/libodb-pgsql/stub.make b/build/export/libodb-pgsql/stub.make index 8dd5e22..9e646aa 100644 --- a/build/export/libodb-pgsql/stub.make +++ b/build/export/libodb-pgsql/stub.make @@ -1,5 +1,4 @@ # file : build/export/libodb-pgsql/stub.make -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file $(call include-once,$(src_root)/odb/pgsql/makefile,$(out_root)) diff --git a/build/import/cli/LICENSE b/build/import/cli/LICENSE deleted file mode 100644 index f6b2d2b..0000000 --- a/build/import/cli/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2009-2019 Code Synthesis Tools CC. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/build/import/cli/cli-cxx.make b/build/import/cli/cli-cxx.make index 3d01453..9bdf238 100644 --- a/build/import/cli/cli-cxx.make +++ b/build/import/cli/cli-cxx.make @@ -1,5 +1,4 @@ # file : build/import/cli/cli-cxx.make -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : MIT; see accompanying LICENSE file # Here we are operating in the importing project's space, not in diff --git a/build/import/cli/configuration-rules.make b/build/import/cli/configuration-rules.make index f13d01b..6355000 100644 --- a/build/import/cli/configuration-rules.make +++ b/build/import/cli/configuration-rules.make @@ -1,5 +1,4 @@ # file : build/import/cli/configuration-rules.make -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : MIT; see accompanying LICENSE file $(dcf_root)/import/cli/configuration-dynamic.make: | $(dcf_root)/import/cli/. diff --git a/build/import/cli/configure b/build/import/cli/configure index 944f48c..2a1fde4 100755 --- a/build/import/cli/configure +++ b/build/import/cli/configure @@ -1,7 +1,6 @@ #! /usr/bin/env bash # file : build/import/cli/configure -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : MIT; see accompanying LICENSE file diff --git a/build/import/cli/stub.make b/build/import/cli/stub.make index 047ba40..741b371 100644 --- a/build/import/cli/stub.make +++ b/build/import/cli/stub.make @@ -1,5 +1,4 @@ # file : build/import/cli/stub.make -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : MIT; see accompanying LICENSE file $(call include-once,$(scf_root)/import/cli/configuration-rules.make,$(dcf_root)) diff --git a/build/import/libodb-pgsql/LICENSE b/build/import/libodb-pgsql/LICENSE deleted file mode 120000 index 5853aae..0000000 --- a/build/import/libodb-pgsql/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../../LICENSE
\ No newline at end of file diff --git a/build/import/libodb-pgsql/configuration-rules.make b/build/import/libodb-pgsql/configuration-rules.make index 7ba6f62..326a60c 100644 --- a/build/import/libodb-pgsql/configuration-rules.make +++ b/build/import/libodb-pgsql/configuration-rules.make @@ -1,5 +1,4 @@ # file : build/import/libodb-pgsql/configuration-rules.make -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file $(dcf_root)/import/libodb-pgsql/configuration-dynamic.make: | $(dcf_root)/import/libodb-pgsql/. diff --git a/build/import/libodb-pgsql/configure b/build/import/libodb-pgsql/configure index 3918fb9..9d75cad 100755 --- a/build/import/libodb-pgsql/configure +++ b/build/import/libodb-pgsql/configure @@ -1,7 +1,6 @@ #! /usr/bin/env bash # file : build/import/libodb-pgsql/configure -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file diff --git a/build/import/libodb-pgsql/stub.make b/build/import/libodb-pgsql/stub.make index 2e5a38d..b770a63 100644 --- a/build/import/libodb-pgsql/stub.make +++ b/build/import/libodb-pgsql/stub.make @@ -1,5 +1,4 @@ # file : build/import/libodb-pgsql/stub.make -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file $(call include-once,$(scf_root)/import/libodb-pgsql/configuration-rules.make,$(dcf_root)) diff --git a/build/import/libodb/LICENSE b/build/import/libodb/LICENSE deleted file mode 100644 index ed9c55c..0000000 --- a/build/import/libodb/LICENSE +++ /dev/null @@ -1,12 +0,0 @@ -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License version 2 as -published by the Free Software Foundation. - -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 -GNU General Public License for details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/build/import/libodb/configuration-rules.make b/build/import/libodb/configuration-rules.make index 872cbb3..340c418 100644 --- a/build/import/libodb/configuration-rules.make +++ b/build/import/libodb/configuration-rules.make @@ -1,5 +1,4 @@ # file : build/import/libodb/configuration-rules.make -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file $(dcf_root)/import/libodb/configuration-dynamic.make: | $(dcf_root)/import/libodb/. diff --git a/build/import/libodb/configure b/build/import/libodb/configure index 0d57a5f..261a202 100755 --- a/build/import/libodb/configure +++ b/build/import/libodb/configure @@ -1,7 +1,6 @@ #! /usr/bin/env bash # file : build/import/libodb/configure -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file diff --git a/build/import/libodb/stub.make b/build/import/libodb/stub.make index 6b7088d..04dc786 100644 --- a/build/import/libodb/stub.make +++ b/build/import/libodb/stub.make @@ -1,5 +1,4 @@ # file : build/import/libodb/stub.make -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file $(call include-once,$(scf_root)/import/libodb/configuration-rules.make,$(dcf_root)) diff --git a/build/import/libpq/LICENSE b/build/import/libpq/LICENSE deleted file mode 100644 index 3912109..0000000 --- a/build/import/libpq/LICENSE +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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 - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/build/import/libpq/configuration-rules.make b/build/import/libpq/configuration-rules.make index b117767..3b43941 100644 --- a/build/import/libpq/configuration-rules.make +++ b/build/import/libpq/configuration-rules.make @@ -1,5 +1,4 @@ # file : build/import/libpq/configuration-rules.make -# copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file $(dcf_root)/import/libpq/configuration-dynamic.make: | $(dcf_root)/import/libpq/. diff --git a/build/import/libpq/configure b/build/import/libpq/configure index 56f5c3f..91b196f 100755 --- a/build/import/libpq/configure +++ b/build/import/libpq/configure @@ -1,7 +1,6 @@ #! /usr/bin/env bash # file : build/import/libpq/configure -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file diff --git a/build/import/libpq/rules.make b/build/import/libpq/rules.make index dee718f..016a671 100644 --- a/build/import/libpq/rules.make +++ b/build/import/libpq/rules.make @@ -1,5 +1,4 @@ # file : build/import/libpq/rules.make -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file $(dcf_root)/import/libpq/%: root := $(libpq_root) diff --git a/build/import/libpq/stub.make b/build/import/libpq/stub.make index a8f8824..94ba269 100644 --- a/build/import/libpq/stub.make +++ b/build/import/libpq/stub.make @@ -1,5 +1,4 @@ # file : build/import/libpq/stub.make -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file $(call include-once,$(scf_root)/import/libpq/configuration-rules.make,$(dcf_root)) diff --git a/build/root.build b/build/root.build index ece30fb..329cc45 100644 --- a/build/root.build +++ b/build/root.build @@ -1,7 +1,8 @@ # file : build/root.build -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file +config [bool] config.libodb_pgsql.develop ?= false + cxx.std = latest using cxx @@ -16,11 +17,3 @@ if ($cxx.target.system == 'win32-msvc') if ($cxx.class == 'msvc') cxx.coptions += /wd4251 /wd4275 /wd4800 - -# Load the cli module but only if it's available. This way a distribution -# that includes pre-generated files can be built without installing cli. -# This is also the reason why we need to explicitly spell out individual -# source file prerequisites instead of using the cli.cxx{} group (it won't -# be there unless the module is configured). -# -using? cli @@ -1,8 +1,7 @@ # file : buildfile -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file -./: {*/ -build/ -m4/} doc{GPLv2 INSTALL LICENSE NEWS README} manifest +./: {*/ -build/ -m4/} doc{INSTALL NEWS README} legal{GPLv2 LICENSE} manifest # Don't install tests or the INSTALL file. # diff --git a/configure.ac b/configure.ac index 3e609fe..f09dc37 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,4 @@ # file : configure.ac -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file AC_PREREQ(2.60) diff --git a/libodb-pgsql.pc.in b/libodb-pgsql.pc.in index a3cefb4..63c6966 100644 --- a/libodb-pgsql.pc.in +++ b/libodb-pgsql.pc.in @@ -1,5 +1,4 @@ # file : libodb-pgsql.pc.in -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file prefix=@prefix@ diff --git a/m4/disable-rpath.m4 b/m4/disable-rpath.m4 index 7874d4b..0864209 100644 --- a/m4/disable-rpath.m4 +++ b/m4/disable-rpath.m4 @@ -1,5 +1,4 @@ dnl file : m4/disable-rpath.m4 -dnl copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC dnl license : GNU GPL v2; see accompanying LICENSE file dnl AC_DEFUN([DISABLE_RPATH],[ diff --git a/m4/libodb.m4 b/m4/libodb.m4 index 5f140bd..0dba7c4 100644 --- a/m4/libodb.m4 +++ b/m4/libodb.m4 @@ -1,5 +1,4 @@ dnl file : m4/libodb.m4 -dnl copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC dnl license : GNU GPL v2; see accompanying LICENSE file dnl dnl LIBODB([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) diff --git a/m4/libpq.m4 b/m4/libpq.m4 index 1529fbd..a29ae2d 100644 --- a/m4/libpq.m4 +++ b/m4/libpq.m4 @@ -1,5 +1,4 @@ dnl file : m4/libpq.m4 -dnl copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC dnl license : GNU GPL v2; see accompanying LICENSE file dnl dnl LIBPQ([ACTION-IF-FOUND[, diff --git a/m4/libtool-link.m4 b/m4/libtool-link.m4 index 635793f..302639f 100644 --- a/m4/libtool-link.m4 +++ b/m4/libtool-link.m4 @@ -1,5 +1,4 @@ dnl file : m4/libtool-link.m4 -dnl copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC dnl license : GNU GPL v2; see accompanying LICENSE file dnl dnl diff --git a/m4/pkgconfig.m4 b/m4/pkgconfig.m4 index d5aa2d0..c48ea56 100644 --- a/m4/pkgconfig.m4 +++ b/m4/pkgconfig.m4 @@ -1,5 +1,4 @@ dnl file : m4/pkgconfig.m4 -dnl copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC dnl license : GNU GPL v2; see accompanying LICENSE file dnl AC_DEFUN([PKGCONFIG],[ diff --git a/m4/static-lib.m4 b/m4/static-lib.m4 index 79b89cd..5fb1c11 100644 --- a/m4/static-lib.m4 +++ b/m4/static-lib.m4 @@ -1,5 +1,4 @@ dnl file : m4/static-lib.m4 -dnl copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC dnl license : GNU GPL v2; see accompanying LICENSE file dnl dnl STATIC_LIB(MACRO, DESCRIPTION) diff --git a/m4/threads.m4 b/m4/threads.m4 index 10bdfdd..6f2e25f 100644 --- a/m4/threads.m4 +++ b/m4/threads.m4 @@ -1,5 +1,4 @@ dnl file : m4/threads.m4 -dnl copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC dnl license : GNU GPL v2; see accompanying LICENSE file dnl AC_DEFUN([THREADS],[ @@ -1,5 +1,4 @@ # file : makefile -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file include $(dir $(lastword $(MAKEFILE_LIST)))build/bootstrap.make @@ -13,12 +12,12 @@ clean := $(out_base)/.clean $(default): $(addprefix $(out_base)/,$(addsuffix /,$(dirs))) $(dist): export dirs := $(dirs) -$(dist): export docs := GPLv2 LICENSE README NEWS version +$(dist): export docs := GPLv2 LICENSE README NEWS version.txt $(dist): data_dist := INSTALL libodb-pgsql-vc8.sln libodb-pgsql-vc9.sln \ libodb-pgsql-vc10.sln libodb-pgsql-vc11.sln libodb-pgsql-vc12.sln $(dist): exec_dist := bootstrap $(dist): export extra_dist := $(data_dist) $(exec_dist) -$(dist): export version = $(shell cat $(src_root)/version) +$(dist): export version = $(shell cat $(src_root)/version.txt) $(dist): $(addprefix $(out_base)/,$(addsuffix /.dist,$(dirs))) $(call dist-data,$(docs) $(data_dist) libodb-pgsql.pc.in) @@ -1,10 +1,10 @@ : 1 name: libodb-pgsql -version: 2.5.0-b.16.z +version: 2.5.0-b.26.z project: odb summary: PostgreSQL ODB runtime library -license: GPLv2 -license: proprietary +license: GPL-2.0-only +license: other: proprietary ; Not free/open source. topics: C++, ORM, PostgreSQL, SQL description-file: README changes-file: NEWS @@ -12,10 +12,12 @@ 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-pgsql/ email: odb-users@codesynthesis.com -build-email: odb-builds@codesynthesis.com +build-warning-email: odb-builds@codesynthesis.com builds: all +builds: -wasm requires: c++11 -depends: * build2 >= 0.11.0 -depends: * bpkg >= 0.11.0 -depends: libpq ^9.0.0 -depends: libodb [2.5.0-b.16.1 2.5.0-b.17) +depends: * build2 >= 0.16.0- +depends: * bpkg >= 0.16.0- +depends: libpq >=7.4.0 +depends: libodb [2.5.0-b.26.1 2.5.0-b.27) +depends: * cli ^1.2.0- ? ($config.libodb_pgsql.develop) diff --git a/odb/pgsql/Makefile.am b/odb/pgsql/Makefile.am index 47410bc..8a95b93 100644 --- a/odb/pgsql/Makefile.am +++ b/odb/pgsql/Makefile.am @@ -1,5 +1,4 @@ # file : odb/pgsql/Makefile.am -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file lib_LTLIBRARIES = libodb-pgsql.la diff --git a/odb/pgsql/auto-handle.cxx b/odb/pgsql/auto-handle.cxx index e8e426a..d6c0565 100644 --- a/odb/pgsql/auto-handle.cxx +++ b/odb/pgsql/auto-handle.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/auto-handle.cxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <libpq-fe.h> diff --git a/odb/pgsql/auto-handle.hxx b/odb/pgsql/auto-handle.hxx index a2dd92b..49b396d 100644 --- a/odb/pgsql/auto-handle.hxx +++ b/odb/pgsql/auto-handle.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/auto-handle.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_AUTO_HANDLE_HXX diff --git a/odb/pgsql/binding.hxx b/odb/pgsql/binding.hxx index 468a6e9..1adf144 100644 --- a/odb/pgsql/binding.hxx +++ b/odb/pgsql/binding.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/binding.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_BINDING_HXX @@ -42,17 +41,27 @@ namespace odb public: typedef pgsql::bind bind_type; - binding (): bind (0), count (0), version (0) {} + binding () + : bind (0), count (0), version (0), + batch (0), skip (0), status (0) {} binding (bind_type* b, std::size_t n) - : bind (b), count (n), version (0) - { - } + : bind (b), count (n), version (0), + batch (0), skip (0), status (0) {} + + binding (bind_type* b, std::size_t n, + std::size_t bt, std::size_t s, unsigned long long* st) + : bind (b), count (n), version (0), + batch (bt), skip (s), status (st) {} bind_type* bind; std::size_t count; std::size_t version; + std::size_t batch; + std::size_t skip; + unsigned long long* status; // Batch status array. + private: binding (const binding&); binding& operator= (const binding&); diff --git a/odb/pgsql/buildfile b/odb/pgsql/buildfile index c2bb0d4..f1d05b6 100644 --- a/odb/pgsql/buildfile +++ b/odb/pgsql/buildfile @@ -1,13 +1,15 @@ # file : odb/pgsql/buildfile -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file +define cli: file +cli{*}: extension = cli + import int_libs = libodb%lib{odb} import imp_libs = libpq%lib{pq} -lib{odb-pgsql}: {hxx ixx txx cxx}{* -version-build2} {hxx}{version-build2} \ - details/{hxx ixx txx cxx}{* -options} details/{hxx ixx cxx}{options} \ - details/build2/{h}{*} \ +lib{odb-pgsql}: {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 @@ -48,36 +50,76 @@ if $version.pre_release else lib{odb-pgsql}: bin.lib.version = @"-$version.major.$version.minor" -# Generated options parser. +develop = $config.libodb_pgsql.develop + +## Consumption build ($develop == false). +# + +# Use pregenerated versions in the consumption build. +# +lib{odb-pgsql}: 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) + # -details/ +## + +## Development build ($develop == true). +# + +lib{odb-pgsql}: 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/{hxx ixx cxx}{options}>: details/cli{options} $cli { - if $cli.configured - { - cli.cxx{options}: cli{options} - - cli.options += --include-with-brackets --include-prefix odb/pgsql/details \ ---guard-prefix LIBODB_PGSQL_DETAILS --generate-file-scanner \ ---cli-namespace odb::pgsql::details::cli --long-usage --generate-specifier \ ---no-combined-flags - - # Include generated cli files into the distribution and don't remove them - # when cleaning in src (so that clean results in a state identical to - # distributed). But don't install their headers since they are only used - # internally in the database implementation. - # - cli.cxx{*}: - { - dist = true - clean = ($src_root != $out_root) - install = false - } - } - else - # No install for the pre-generated case. - # - hxx{options}@./ ixx{options}@./: install = false + install = false + dist = ($develop ? pregenerated/odb/pgsql/details/ : false) + + # Symlink the generated code in src for convenience of development. + # + backlink = true } +% +if $develop +{{ + options = --include-with-brackets --include-prefix odb/pgsql/details \ + --guard-prefix LIBODB_PGSQL_DETAILS --generate-file-scanner \ + --cli-namespace odb::pgsql::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/pgsql/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/pgsql/ subdirectory of, say, /usr/include/ # recreating subdirectories. @@ -100,7 +142,7 @@ details/build2/ { h{*}: install = false - if ($cxx.class == 'msvc') + 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 diff --git a/odb/pgsql/connection-factory.cxx b/odb/pgsql/connection-factory.cxx index 6597c8b..855a9bc 100644 --- a/odb/pgsql/connection-factory.cxx +++ b/odb/pgsql/connection-factory.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/connection-factory.cxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/pgsql/connection-factory.hxx> diff --git a/odb/pgsql/connection-factory.hxx b/odb/pgsql/connection-factory.hxx index c3b95a0..2f300a8 100644 --- a/odb/pgsql/connection-factory.hxx +++ b/odb/pgsql/connection-factory.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/connection-factory.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_CONNECTION_FACTORY_HXX diff --git a/odb/pgsql/connection.cxx b/odb/pgsql/connection.cxx index cc6620a..80a1dd2 100644 --- a/odb/pgsql/connection.cxx +++ b/odb/pgsql/connection.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/connection.cxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <new> // std::bad_alloc diff --git a/odb/pgsql/connection.hxx b/odb/pgsql/connection.hxx index 4f8b8b0..d779273 100644 --- a/odb/pgsql/connection.hxx +++ b/odb/pgsql/connection.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/connection.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_CONNECTION_HXX diff --git a/odb/pgsql/connection.ixx b/odb/pgsql/connection.ixx index 4b29999..76d558b 100644 --- a/odb/pgsql/connection.ixx +++ b/odb/pgsql/connection.ixx @@ -1,5 +1,4 @@ // file : odb/pgsql/connection.ixx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file namespace odb diff --git a/odb/pgsql/container-statements.hxx b/odb/pgsql/container-statements.hxx index c387dce..1856bb9 100644 --- a/odb/pgsql/container-statements.hxx +++ b/odb/pgsql/container-statements.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/container-statements.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_CONTAINER_STATEMENTS_HXX diff --git a/odb/pgsql/container-statements.txx b/odb/pgsql/container-statements.txx index 86fea2a..34eb99f 100644 --- a/odb/pgsql/container-statements.txx +++ b/odb/pgsql/container-statements.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/container-statements.txx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cstddef> // std::size_t diff --git a/odb/pgsql/database.cxx b/odb/pgsql/database.cxx index 8c4c99f..09bf6f0 100644 --- a/odb/pgsql/database.cxx +++ b/odb/pgsql/database.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/database.cxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cstring> // strlen() @@ -250,10 +249,11 @@ namespace odb // Bind parameters and results. // + char* pbuf[1] = {const_cast<char*> (name.c_str ())}; size_t psize[1] = {name.size ()}; bool pnull[1] = {false}; bind pbind[1] = {{bind::text, - const_cast<char*> (name.c_str ()), + &pbuf[0], &psize[0], psize[0], &pnull[0], @@ -283,7 +283,9 @@ namespace odb cp = factory_->connect (); pgsql::connection& c ( - cp != 0 ? *cp : transaction::current ().connection ()); + cp != 0 + ? *cp + : transaction::current ().connection (const_cast<database&> (*this))); // If we are in the user's transaction then things are complicated. When // we try to execute SELECT on a non-existent table, PG "poisons" the @@ -301,10 +303,11 @@ namespace odb bool exists (true); if (cp == 0 && c.server_version () >= 90400) { + char* pbuf[1] = {const_cast<char*> (table)}; size_t psize[1] = {strlen (table)}; bool pnull[1] = {false}; bind pbind[1] = {{bind::text, - const_cast<char*> (table), + &pbuf[0], &psize[0], psize[0], &pnull[0], @@ -320,7 +323,7 @@ namespace odb native_binding nparam (values, lengths, formats, 1); bool rnull[1]; - bind rbind[1] = {{bind::boolean_, &exists, 0, 0, &rnull[1], 0}}; + bind rbind[1] = {{bind::boolean_, &exists, 0, 0, &rnull[0], 0}}; binding result (rbind, 1); result.version++; diff --git a/odb/pgsql/database.hxx b/odb/pgsql/database.hxx index 2e5f158..950cad1 100644 --- a/odb/pgsql/database.hxx +++ b/odb/pgsql/database.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/database.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_DATABASE_HXX @@ -80,6 +79,9 @@ namespace odb // Move-constructible but not move-assignable. // + // Note: noexcept is not specified since odb::database(odb::database&&) + // can throw. + // #ifdef ODB_CXX11 database (database&&); #endif @@ -125,6 +127,13 @@ namespace odb typename object_traits<T>::id_type persist (const typename object_traits<T>::pointer_type& obj_ptr); + // Bulk persist. Can be a range of references or pointers (including + // smart pointers) to objects. + // + template <typename I> + void + persist (I begin, I end, bool continue_failed = true); + // Load an object. Throw object_not_persistent if not found. // template <typename T> @@ -211,6 +220,13 @@ namespace odb void update (const typename object_traits<T>::pointer_type& obj_ptr); + // Bulk update. Can be a range of references or pointers (including + // smart pointers) to objects. + // + template <typename I> + 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. @@ -254,6 +270,19 @@ namespace odb void erase (const typename object_traits<T>::pointer_type& obj_ptr); + // Bulk erase. + // + template <typename T, typename I> + 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 <typename I> + void + erase (I obj_begin, I obj_end, bool continue_failed = true); + // Erase multiple objects matching a query predicate. // template <typename T> diff --git a/odb/pgsql/database.ixx b/odb/pgsql/database.ixx index 67c8470..f04c3e6 100644 --- a/odb/pgsql/database.ixx +++ b/odb/pgsql/database.ixx @@ -1,5 +1,4 @@ // file : odb/pgsql/database.ixx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <utility> // move() @@ -120,6 +119,13 @@ namespace odb return persist_<T, id_pgsql> (pobj); } + template <typename I> + inline void database:: + persist (I b, I e, bool cont) + { + persist_<I, id_pgsql> (b, e, cont); + } + template <typename T> inline typename object_traits<T>::pointer_type database:: load (const typename object_traits<T>::id_type& id) @@ -281,6 +287,13 @@ namespace odb update_<T, id_pgsql> (pobj); } + template <typename I> + inline void database:: + update (I b, I e, bool cont) + { + update_<I, id_pgsql> (b, e, cont); + } + template <typename T> inline void database:: update (const T& obj, const section& s) @@ -370,6 +383,20 @@ namespace odb erase_<T, id_pgsql> (pobj); } + template <typename T, typename I> + inline void database:: + erase (I idb, I ide, bool cont) + { + erase_id_<I, T, id_pgsql> (idb, ide, cont); + } + + template <typename I> + inline void database:: + erase (I ob, I oe, bool cont) + { + erase_object_<I, id_pgsql> (ob, oe, cont); + } + template <typename T> inline unsigned long long database:: erase_query () @@ -595,7 +622,7 @@ namespace odb { // Throws if not in transaction. // - pgsql::connection& c (transaction::current ().connection ()); + pgsql::connection& c (transaction::current ().connection (*this)); return c.prepare_query<T> (n, q); } diff --git a/odb/pgsql/details/.gitignore b/odb/pgsql/details/.gitignore index c6e608b..b298f89 100644 --- a/odb/pgsql/details/.gitignore +++ b/odb/pgsql/details/.gitignore @@ -1 +1 @@ -options.?xx +/options.?xx diff --git a/odb/pgsql/details/build2/config-stub.h b/odb/pgsql/details/build2/config-stub.h index 24aed55..00c5940 100644 --- a/odb/pgsql/details/build2/config-stub.h +++ b/odb/pgsql/details/build2/config-stub.h @@ -1,5 +1,4 @@ /* file : odb/pgsql/details/build2/config-stub.h - * copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC * license : GNU GPL v2; see accompanying LICENSE file */ diff --git a/odb/pgsql/details/build2/config-vc-stub.h b/odb/pgsql/details/build2/config-vc-stub.h index 3bf175e..473cd96 100644 --- a/odb/pgsql/details/build2/config-vc-stub.h +++ b/odb/pgsql/details/build2/config-vc-stub.h @@ -1,5 +1,4 @@ /* file : odb/pgsql/details/build2/config-vc-stub.h - * copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC * license : GNU GPL v2; see accompanying LICENSE file */ diff --git a/odb/pgsql/details/build2/config-vc.h b/odb/pgsql/details/build2/config-vc.h index 006837d..e9d9ade 100644 --- a/odb/pgsql/details/build2/config-vc.h +++ b/odb/pgsql/details/build2/config-vc.h @@ -1,5 +1,4 @@ /* file : odb/pgsql/details/build2/config-vc.h - * copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC * license : GNU GPL v2; see accompanying LICENSE file */ diff --git a/odb/pgsql/details/build2/config.h b/odb/pgsql/details/build2/config.h index 3de4c9c..b2a81b5 100644 --- a/odb/pgsql/details/build2/config.h +++ b/odb/pgsql/details/build2/config.h @@ -1,5 +1,4 @@ /* file : odb/pgsql/details/build2/config.h - * copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC * license : GNU GPL v2; see accompanying LICENSE file */ diff --git a/odb/pgsql/details/config-vc.h b/odb/pgsql/details/config-vc.h index 0614fde..77a0be5 100644 --- a/odb/pgsql/details/config-vc.h +++ b/odb/pgsql/details/config-vc.h @@ -1,5 +1,4 @@ /* file : odb/pgsql/details/config-vc.h - * copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC * license : GNU GPL v2; see accompanying LICENSE file */ diff --git a/odb/pgsql/details/config.h.in b/odb/pgsql/details/config.h.in index fcf2202..889023c 100644 --- a/odb/pgsql/details/config.h.in +++ b/odb/pgsql/details/config.h.in @@ -1,5 +1,4 @@ /* file : odb/pgsql/details/config.h.in - * copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC * license : GNU GPL v2; see accompanying LICENSE file */ diff --git a/odb/pgsql/details/config.hxx b/odb/pgsql/details/config.hxx index 07cf541..1340622 100644 --- a/odb/pgsql/details/config.hxx +++ b/odb/pgsql/details/config.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/details/config.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_DETAILS_CONFIG_HXX diff --git a/odb/pgsql/details/conversion.hxx b/odb/pgsql/details/conversion.hxx index 1033c29..b4d7e4f 100644 --- a/odb/pgsql/details/conversion.hxx +++ b/odb/pgsql/details/conversion.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/details/conversion.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_DETAILS_CONVERSION_HXX diff --git a/odb/pgsql/details/endian-traits.cxx b/odb/pgsql/details/endian-traits.cxx index 1c74878..77fdc95 100644 --- a/odb/pgsql/details/endian-traits.cxx +++ b/odb/pgsql/details/endian-traits.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/details/endian-traits.cxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/pgsql/details/endian-traits.hxx> diff --git a/odb/pgsql/details/endian-traits.hxx b/odb/pgsql/details/endian-traits.hxx index d02a7b2..532a4a3 100644 --- a/odb/pgsql/details/endian-traits.hxx +++ b/odb/pgsql/details/endian-traits.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/details/endian-traits.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_DETAILS_ENDIAN_TRAITS_HXX diff --git a/odb/pgsql/details/export.hxx b/odb/pgsql/details/export.hxx index 3b86702..81ff6a0 100644 --- a/odb/pgsql/details/export.hxx +++ b/odb/pgsql/details/export.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/details/export.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_DETAILS_EXPORT_HXX diff --git a/odb/pgsql/details/options.cli b/odb/pgsql/details/options.cli index 886a869..f568236 100644 --- a/odb/pgsql/details/options.cli +++ b/odb/pgsql/details/options.cli @@ -1,5 +1,4 @@ // file : odb/pgsql/details/options.cli -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file include <string>; diff --git a/odb/pgsql/details/pregenerated/odb/pgsql/details/options.cxx b/odb/pgsql/details/pregenerated/odb/pgsql/details/options.cxx new file mode 100644 index 0000000..a4a5da6 --- /dev/null +++ b/odb/pgsql/details/pregenerated/odb/pgsql/details/options.cxx @@ -0,0 +1,1114 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +// Begin prologue. +// +// +// End prologue. + +#include <odb/pgsql/details/options.hxx> + +#include <map> +#include <set> +#include <string> +#include <vector> +#include <utility> +#include <ostream> +#include <sstream> +#include <cstring> +#include <fstream> + +namespace odb +{ + namespace pgsql + { + 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 <typename X> + 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<bool> + { + 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<std::string> + { + 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 <typename X> + struct parser<std::pair<X, std::size_t> > + { + static void + parse (std::pair<X, std::size_t>& x, bool& xs, scanner& s) + { + x.second = s.position (); + parser<X>::parse (x.first, xs, s); + } + }; + + template <typename X> + struct parser<std::vector<X> > + { + static void + parse (std::vector<X>& c, bool& xs, scanner& s) + { + X x; + bool dummy; + parser<X>::parse (x, dummy, s); + c.push_back (x); + xs = true; + } + }; + + template <typename X, typename C> + struct parser<std::set<X, C> > + { + static void + parse (std::set<X, C>& c, bool& xs, scanner& s) + { + X x; + bool dummy; + parser<X>::parse (x, dummy, s); + c.insert (x); + xs = true; + } + }; + + template <typename K, typename V, typename C> + struct parser<std::map<K, V, C> > + { + static void + parse (std::map<K, V, C>& 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<char*> (o), + 0 + }; + + bool dummy; + if (!kstr.empty ()) + { + av[1] = const_cast<char*> (kstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser<K>::parse (k, dummy, s); + } + + if (!vstr.empty ()) + { + av[1] = const_cast<char*> (vstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser<V>::parse (v, dummy, s); + } + + m[k] = v; + } + else + throw missing_value (o); + + xs = true; + } + }; + + template <typename K, typename V, typename C> + struct parser<std::multimap<K, V, C> > + { + static void + parse (std::multimap<K, V, C>& 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<char*> (o), + 0 + }; + + bool dummy; + if (!kstr.empty ()) + { + av[1] = const_cast<char*> (kstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser<K>::parse (k, dummy, s); + } + + if (!vstr.empty ()) + { + av[1] = const_cast<char*> (vstr.c_str ()); + argv_scanner s (0, ac, av, false, pos); + parser<V>::parse (v, dummy, s); + } + + m.insert (typename std::multimap<K, V, C>::value_type (k, v)); + } + else + throw missing_value (o); + + xs = true; + } + }; + + template <typename X, typename T, T X::*M> + void + thunk (X& x, scanner& s) + { + parser<T>::parse (x.*M, s); + } + + template <typename X, bool X::*M> + void + thunk (X& x, scanner& s) + { + s.next (); + x.*M = true; + } + + template <typename X, typename T, T X::*M, bool X::*S> + void + thunk (X& x, scanner& s) + { + parser<T>::parse (x.*M, x.*S, s); + } + } + } + } +} + +#include <map> + +namespace odb +{ + namespace pgsql + { + namespace details + { + // options + // + + options:: + options () + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + host_ (), + host_specified_ (false), + port_ (), + port_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + } + + options:: + options (int& argc, + char** argv, + bool erase, + ::odb::pgsql::details::cli::unknown_mode opt, + ::odb::pgsql::details::cli::unknown_mode arg) + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + host_ (), + host_specified_ (false), + port_ (), + port_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + ::odb::pgsql::details::cli::argv_scanner s (argc, argv, erase); + _parse (s, opt, arg); + } + + options:: + options (int start, + int& argc, + char** argv, + bool erase, + ::odb::pgsql::details::cli::unknown_mode opt, + ::odb::pgsql::details::cli::unknown_mode arg) + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + host_ (), + host_specified_ (false), + port_ (), + port_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + ::odb::pgsql::details::cli::argv_scanner s (start, argc, argv, erase); + _parse (s, opt, arg); + } + + options:: + options (int& argc, + char** argv, + int& end, + bool erase, + ::odb::pgsql::details::cli::unknown_mode opt, + ::odb::pgsql::details::cli::unknown_mode arg) + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + host_ (), + host_specified_ (false), + port_ (), + port_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + ::odb::pgsql::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::pgsql::details::cli::unknown_mode opt, + ::odb::pgsql::details::cli::unknown_mode arg) + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + host_ (), + host_specified_ (false), + port_ (), + port_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + ::odb::pgsql::details::cli::argv_scanner s (start, argc, argv, erase); + _parse (s, opt, arg); + end = s.end (); + } + + options:: + options (::odb::pgsql::details::cli::scanner& s, + ::odb::pgsql::details::cli::unknown_mode opt, + ::odb::pgsql::details::cli::unknown_mode arg) + : user_ (), + user_specified_ (false), + password_ (), + password_specified_ (false), + database_ (), + database_specified_ (false), + host_ (), + host_specified_ (false), + port_ (), + port_specified_ (false), + options_file_ (), + options_file_specified_ (false) + { + _parse (s, opt, arg); + } + + ::odb::pgsql::details::cli::usage_para options:: + print_usage (::std::ostream& os, ::odb::pgsql::details::cli::usage_para p) + { + CLI_POTENTIALLY_UNUSED (os); + + if (p != ::odb::pgsql::details::cli::usage_para::none) + os << ::std::endl; + + os << "--user|--username <name> PostgreSQL database user." << ::std::endl; + + os << std::endl + << "--password <str> PostgreSQL database password." << ::std::endl; + + os << std::endl + << "--database|--dbname <name> PostgreSQL database name." << ::std::endl; + + os << std::endl + << "--host <str> PostgreSQL database host name or address (localhost" << ::std::endl + << " by default)." << ::std::endl; + + os << std::endl + << "--port <str> PostgreSQL database port number or socket file name" << ::std::endl + << " extension for Unix-domain connections." << ::std::endl; + + os << std::endl + << "--options-file <file> Read additional options from <file>. Each option" << ::std::endl + << " should appear on a separate line optionally followed" << ::std::endl + << " by space or equal sign (=) and an option value." << ::std::endl + << " Empty lines and lines starting with # are ignored." << ::std::endl; + + p = ::odb::pgsql::details::cli::usage_para::option; + + return p; + } + + typedef + std::map<std::string, void (*) (options&, ::odb::pgsql::details::cli::scanner&)> + _cli_options_map; + + static _cli_options_map _cli_options_map_; + + struct _cli_options_map_init + { + _cli_options_map_init () + { + _cli_options_map_["--user"] = + &::odb::pgsql::details::cli::thunk< options, std::string, &options::user_, + &options::user_specified_ >; + _cli_options_map_["--username"] = + &::odb::pgsql::details::cli::thunk< options, std::string, &options::user_, + &options::user_specified_ >; + _cli_options_map_["--password"] = + &::odb::pgsql::details::cli::thunk< options, std::string, &options::password_, + &options::password_specified_ >; + _cli_options_map_["--database"] = + &::odb::pgsql::details::cli::thunk< options, std::string, &options::database_, + &options::database_specified_ >; + _cli_options_map_["--dbname"] = + &::odb::pgsql::details::cli::thunk< options, std::string, &options::database_, + &options::database_specified_ >; + _cli_options_map_["--host"] = + &::odb::pgsql::details::cli::thunk< options, std::string, &options::host_, + &options::host_specified_ >; + _cli_options_map_["--port"] = + &::odb::pgsql::details::cli::thunk< options, std::string, &options::port_, + &options::port_specified_ >; + _cli_options_map_["--options-file"] = + &::odb::pgsql::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::pgsql::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::pgsql::details::cli::scanner& s, + ::odb::pgsql::details::cli::unknown_mode opt_mode, + ::odb::pgsql::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<char*> (co.c_str ()), + const_cast<char*> (v) + }; + + ::odb::pgsql::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::pgsql::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::pgsql::details::cli::unknown_mode::skip: + { + s.skip (); + r = true; + continue; + } + case ::odb::pgsql::details::cli::unknown_mode::stop: + { + break; + } + case ::odb::pgsql::details::cli::unknown_mode::fail: + { + throw ::odb::pgsql::details::cli::unknown_option (o); + } + } + + break; + } + } + + switch (arg_mode) + { + case ::odb::pgsql::details::cli::unknown_mode::skip: + { + s.skip (); + r = true; + continue; + } + case ::odb::pgsql::details::cli::unknown_mode::stop: + { + break; + } + case ::odb::pgsql::details::cli::unknown_mode::fail: + { + throw ::odb::pgsql::details::cli::unknown_argument (o); + } + } + + break; + } + + return r; + } + } + } +} + +// Begin epilogue. +// +// +// End epilogue. + diff --git a/odb/pgsql/details/pregenerated/odb/pgsql/details/options.hxx b/odb/pgsql/details/pregenerated/odb/pgsql/details/options.hxx new file mode 100644 index 0000000..4d264d4 --- /dev/null +++ b/odb/pgsql/details/pregenerated/odb/pgsql/details/options.hxx @@ -0,0 +1,562 @@ +// -*- C++ -*- +// +// This file was generated by CLI, a command line interface +// compiler for C++. +// + +#ifndef LIBODB_PGSQL_DETAILS_OPTIONS_HXX +#define LIBODB_PGSQL_DETAILS_OPTIONS_HXX + +// Begin prologue. +// +// +// End prologue. + +#include <list> +#include <deque> +#include <iosfwd> +#include <string> +#include <cstddef> +#include <exception> + +#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 pgsql + { + 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<arg> args_; + std::list<std::string> 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 <typename X> + struct parser; + } + } + } +} + +#include <string> + +namespace odb +{ + namespace pgsql + { + namespace details + { + class options + { + public: + options (); + + options (int& argc, + char** argv, + bool erase = false, + ::odb::pgsql::details::cli::unknown_mode option = ::odb::pgsql::details::cli::unknown_mode::fail, + ::odb::pgsql::details::cli::unknown_mode argument = ::odb::pgsql::details::cli::unknown_mode::stop); + + options (int start, + int& argc, + char** argv, + bool erase = false, + ::odb::pgsql::details::cli::unknown_mode option = ::odb::pgsql::details::cli::unknown_mode::fail, + ::odb::pgsql::details::cli::unknown_mode argument = ::odb::pgsql::details::cli::unknown_mode::stop); + + options (int& argc, + char** argv, + int& end, + bool erase = false, + ::odb::pgsql::details::cli::unknown_mode option = ::odb::pgsql::details::cli::unknown_mode::fail, + ::odb::pgsql::details::cli::unknown_mode argument = ::odb::pgsql::details::cli::unknown_mode::stop); + + options (int start, + int& argc, + char** argv, + int& end, + bool erase = false, + ::odb::pgsql::details::cli::unknown_mode option = ::odb::pgsql::details::cli::unknown_mode::fail, + ::odb::pgsql::details::cli::unknown_mode argument = ::odb::pgsql::details::cli::unknown_mode::stop); + + options (::odb::pgsql::details::cli::scanner&, + ::odb::pgsql::details::cli::unknown_mode option = ::odb::pgsql::details::cli::unknown_mode::fail, + ::odb::pgsql::details::cli::unknown_mode argument = ::odb::pgsql::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& + host () const; + + bool + host_specified () const; + + const std::string& + port () const; + + bool + port_specified () const; + + const std::string& + options_file () const; + + bool + options_file_specified () const; + + // Print usage information. + // + static ::odb::pgsql::details::cli::usage_para + print_usage (::std::ostream&, + ::odb::pgsql::details::cli::usage_para = ::odb::pgsql::details::cli::usage_para::none); + + // Implementation details. + // + protected: + bool + _parse (const char*, ::odb::pgsql::details::cli::scanner&); + + private: + bool + _parse (::odb::pgsql::details::cli::scanner&, + ::odb::pgsql::details::cli::unknown_mode option, + ::odb::pgsql::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 host_; + bool host_specified_; + std::string port_; + bool port_specified_; + std::string options_file_; + bool options_file_specified_; + }; + } + } +} + +#include <odb/pgsql/details/options.ixx> + +// Begin epilogue. +// +// +// End epilogue. + +#endif // LIBODB_PGSQL_DETAILS_OPTIONS_HXX diff --git a/odb/pgsql/details/pregenerated/odb/pgsql/details/options.ixx b/odb/pgsql/details/pregenerated/odb/pgsql/details/options.ixx new file mode 100644 index 0000000..340789e --- /dev/null +++ b/odb/pgsql/details/pregenerated/odb/pgsql/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 <cassert> + +namespace odb +{ + namespace pgsql + { + 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<std::size_t> (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 pgsql + { + 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:: + host () const + { + return this->host_; + } + + inline bool options:: + host_specified () const + { + return this->host_specified_; + } + + inline const std::string& options:: + port () const + { + return this->port_; + } + + inline bool options:: + port_specified () const + { + return this->port_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/pgsql/error.cxx b/odb/pgsql/error.cxx index 3dfb365..ba8451e 100644 --- a/odb/pgsql/error.cxx +++ b/odb/pgsql/error.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/error.cxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <string> @@ -16,11 +15,12 @@ namespace odb namespace pgsql { void - translate_error (connection& c, PGresult* r) + translate_error (connection& c, PGresult* r, + size_t pos, multiple_exceptions* mex) { if (!r) { - if (CONNECTION_BAD == PQstatus (c.handle ())) + if (PQstatus (c.handle ()) == CONNECTION_BAD) { c.mark_failed (); throw connection_lost (); @@ -29,50 +29,58 @@ namespace odb throw bad_alloc (); } - string msg; - { - // Can be NULL in case of PGRES_BAD_RESPONSE. - // - const char* m (PQresultErrorMessage (r)); - msg = (m != 0 ? m : "bad server response"); - - // Get rid of a trailing newline if there is one. - // - string::size_type n (msg.size ()); - if (n != 0 && msg[n - 1] == '\n') - msg.resize (n - 1); - } - + // Note that we expect the caller to handle PGRES_PIPELINE_ABORTED since + // it's not really an error but rather an indication that no attempt was + // made to execute this statement. + // + string ss; switch (PQresultStatus (r)) { case PGRES_BAD_RESPONSE: { - throw database_exception (msg); + throw database_exception ("bad server response"); } case PGRES_FATAL_ERROR: { - string ss; - { - const char* s (PQresultErrorField (r, PG_DIAG_SQLSTATE)); - ss = (s != 0 ? s : "?????"); - } + const char* s (PQresultErrorField (r, PG_DIAG_SQLSTATE)); + ss = (s != 0 ? s : "?????"); // Deadlock detected. // if (ss == "40001" || ss == "40P01") throw deadlock (); - else if (CONNECTION_BAD == PQstatus (c.handle ())) + else if (PQstatus (c.handle ()) == CONNECTION_BAD) { c.mark_failed (); throw connection_lost (); } - else - throw database_exception (ss, msg); + break; } default: assert (false); break; } + + string msg; + { + // Can be NULL in case of PGRES_BAD_RESPONSE. + // + const char* m (PQresultErrorMessage (r)); + msg = (m != 0 ? m : "bad server response"); + + // Get rid of the trailing newline if there is one. + // + string::size_type n (msg.size ()); + if (n != 0 && msg[n - 1] == '\n') + msg.resize (n - 1); + } + + if (mex == 0) + throw database_exception (ss, msg); + else + // In PosgreSQL all errors are fatal. + // + mex->insert (pos, database_exception (ss, msg), true); } } } diff --git a/odb/pgsql/error.hxx b/odb/pgsql/error.hxx index 18e79aa..8d2793d 100644 --- a/odb/pgsql/error.hxx +++ b/odb/pgsql/error.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/error.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_ERROR_HXX @@ -10,23 +9,25 @@ #include <libpq-fe.h> #include <odb/pgsql/version.hxx> -#include <odb/pgsql/forward.hxx> // connection +#include <odb/pgsql/forward.hxx> // connection, multiple_exceptions #include <odb/pgsql/details/export.hxx> namespace odb { namespace pgsql { - // Translate an error condition involving a PGresult*. If r is null, it is - // assumed that the error was caused due to a bad connection or a memory - // allocation error. + // Translate an error condition involving PGresult* and throw (or return, + // in case multiple_exceptions is not NULL) an appropriate exception. If + // result is NULL, it is assumed that the error was caused due to a bad + // connection or a memory allocation error. // LIBODB_PGSQL_EXPORT void - translate_error (connection& c, PGresult* r); + translate_error (connection& c, PGresult* r, + std::size_t pos = 0, multiple_exceptions* = 0); - // Return true if the PGresult is in an error state. If both s and r are - // non-null, the pointed to value will be populated with the result status. - // Otherwise, s is ignored. + // Return true if PGresult is not NULL and is not in an error state. If + // both s and r are non-NULL, the pointed to value will be populated with + // the result status. Otherwise, s is ignored. // LIBODB_PGSQL_EXPORT bool is_good_result (PGresult* r, ExecStatusType* s = 0); diff --git a/odb/pgsql/error.ixx b/odb/pgsql/error.ixx index f087aeb..6a010aa 100644 --- a/odb/pgsql/error.ixx +++ b/odb/pgsql/error.ixx @@ -1,13 +1,12 @@ // file : odb/pgsql/error.ixx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file namespace odb { namespace pgsql { - bool - inline is_good_result (PGresult* r, ExecStatusType* s) + inline bool + is_good_result (PGresult* r, ExecStatusType* s) { if (r != 0) { @@ -17,9 +16,13 @@ namespace odb *s = status; return - status != PGRES_BAD_RESPONSE && - status != PGRES_NONFATAL_ERROR && - status != PGRES_FATAL_ERROR; + status != PGRES_BAD_RESPONSE + && status != PGRES_NONFATAL_ERROR + && status != PGRES_FATAL_ERROR +#ifdef LIBPQ_HAS_PIPELINING + && status != PGRES_PIPELINE_ABORTED +#endif + ; } return false; diff --git a/odb/pgsql/exceptions.cxx b/odb/pgsql/exceptions.cxx index fd8bb87..28e7fc4 100644 --- a/odb/pgsql/exceptions.cxx +++ b/odb/pgsql/exceptions.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/exceptions.cxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <sstream> @@ -27,7 +26,10 @@ namespace odb const string& message) : sqlstate_ (sqlstate), message_ (message) { - what_ = sqlstate_ + ": " + message_; + if (!sqlstate_.empty ()) + what_ = sqlstate_ + ": " + message_; + else + what_ = message_; } database_exception:: diff --git a/odb/pgsql/exceptions.hxx b/odb/pgsql/exceptions.hxx index ad4fee7..8417c1a 100644 --- a/odb/pgsql/exceptions.hxx +++ b/odb/pgsql/exceptions.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/exceptions.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_EXCEPTIONS_HXX diff --git a/odb/pgsql/forward.hxx b/odb/pgsql/forward.hxx index 8386a56..1186b28 100644 --- a/odb/pgsql/forward.hxx +++ b/odb/pgsql/forward.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/forward.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_FORWARD_HXX diff --git a/odb/pgsql/makefile b/odb/pgsql/makefile index 1e09400..acd23f6 100644 --- a/odb/pgsql/makefile +++ b/odb/pgsql/makefile @@ -1,5 +1,4 @@ # file : odb/pgsql/makefile -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make @@ -110,7 +109,7 @@ libodb-pgsql-vc10.vcxproj libodb-pgsql-vc10.vcxproj.filters \ libodb-pgsql-vc11.vcxproj libodb-pgsql-vc11.vcxproj.filters \ libodb-pgsql-vc12.vcxproj libodb-pgsql-vc12.vcxproj.filters $(dist): export interface_version = $(shell sed -e \ -'s/^\([0-9]*\.[0-9]*\).*/\1/' $(src_root)/version) +'s/^\([0-9]*\.[0-9]*\).*/\1/' $(src_root)/version.txt) $(dist): $(gen) $(call dist-data,$(sources_dist) $(headers_dist) $(data_dist)) diff --git a/odb/pgsql/no-id-object-result.hxx b/odb/pgsql/no-id-object-result.hxx index 7a47d11..734d4a7 100644 --- a/odb/pgsql/no-id-object-result.hxx +++ b/odb/pgsql/no-id-object-result.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/no-id-object-result.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_NO_ID_OBJECT_RESULT_HXX diff --git a/odb/pgsql/no-id-object-result.txx b/odb/pgsql/no-id-object-result.txx index e10036a..0bae952 100644 --- a/odb/pgsql/no-id-object-result.txx +++ b/odb/pgsql/no-id-object-result.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/no-id-object-result.txx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/callback.hxx> diff --git a/odb/pgsql/no-id-object-statements.hxx b/odb/pgsql/no-id-object-statements.hxx index 82e0fe2..baa1b2a 100644 --- a/odb/pgsql/no-id-object-statements.hxx +++ b/odb/pgsql/no-id-object-statements.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/no-id-object-statements.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_NO_ID_OBJECT_STATEMENTS_HXX @@ -49,7 +48,10 @@ namespace odb // Object image. // image_type& - image () {return image_;} + image (std::size_t i = 0) + { + return image_[i]; + } // Insert binding. // @@ -113,7 +115,8 @@ namespace odb no_id_object_statements& operator= (const no_id_object_statements&); private: - image_type image_; + image_type image_[object_traits::batch]; + unsigned long long status_[object_traits::batch]; // Select binding. // diff --git a/odb/pgsql/no-id-object-statements.txx b/odb/pgsql/no-id-object-statements.txx index 83ef2de..0c340ab 100644 --- a/odb/pgsql/no-id-object-statements.txx +++ b/odb/pgsql/no-id-object-statements.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/no-id-object-statements.txx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cstring> // std::memset @@ -25,13 +24,17 @@ namespace odb // select select_image_binding_ (select_image_bind_, select_column_count), // insert - insert_image_binding_ (insert_image_bind_, insert_column_count), + insert_image_binding_ (insert_image_bind_, + insert_column_count, + object_traits::batch, + sizeof (image_type), + status_), insert_image_native_binding_ (insert_image_values_, insert_image_lengths_, insert_image_formats_, insert_column_count) { - image_.version = 0; + image_[0].version = 0; // Only version in the first element used. select_image_version_ = 0; insert_image_version_ = 0; diff --git a/odb/pgsql/pgsql-fwd.hxx b/odb/pgsql/pgsql-fwd.hxx index 317d0c1..e60bc37 100644 --- a/odb/pgsql/pgsql-fwd.hxx +++ b/odb/pgsql/pgsql-fwd.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/pgsql-fwd.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_PGSQL_FWD_HXX diff --git a/odb/pgsql/pgsql-oid.hxx b/odb/pgsql/pgsql-oid.hxx index ca3ae0c..e2ef1af 100644 --- a/odb/pgsql/pgsql-oid.hxx +++ b/odb/pgsql/pgsql-oid.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/pgsql-oid.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file // Generated file of OIDs extracted from the PostgreSQL 8.4.8 source file diff --git a/odb/pgsql/pgsql-types.hxx b/odb/pgsql/pgsql-types.hxx index a397efe..117a41e 100644 --- a/odb/pgsql/pgsql-types.hxx +++ b/odb/pgsql/pgsql-types.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/pgsql-types.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_PGSQL_TYPES_HXX @@ -15,8 +14,13 @@ namespace odb { namespace pgsql { - // The libpq result binding. This data structures is - // modelled after MYSQL_BIND from MySQL. + // The libpq result binding. This data structures is roughly modeled + // after MYSQL_BIND from MySQL. + // + // Types that may need to grow are bound as pointers to pointers to char + // array (normally in details::buffer) in order to allow simple offsetting + // in bulk operation support. Note that if we were to do the same for + // capacity, we could get rid of the buffer growth tracking altogether. // struct bind { @@ -28,14 +32,14 @@ namespace odb bigint, // Buffer is long long; size, capacity, truncated are unused. real, // Buffer is float; size, capacity, truncated are unused. double_, // Buffer is double; size, capacity, truncated are unused. - numeric, // Buffer is a char array. + numeric, // Buffer is a pointer to pointer to char array. date, // Buffer is int; size, capacity, truncated are unused. time, // Buffer is long long; size, capacity, truncated are unused. timestamp,// Buffer is long long; size, capacity, truncated are unused. - text, // Buffer is a char array. - bytea, // Buffer is a char array. - bit, // Buffer is a char array. - varbit, // Buffer is a char array. + text, // Buffer is a pointer to pointer to char array. + bytea, // Buffer is a pointer to pointer to char array. + bit, // Buffer is a pointer to char array. + varbit, // Buffer is a pointer to pointer to char array. uuid // Buffer is a 16-byte char array; size capacity, truncated // are unused. Note: big-endian, in RFC 4122/4.1.2 order. }; diff --git a/odb/pgsql/polymorphic-object-result.hxx b/odb/pgsql/polymorphic-object-result.hxx index c0a49e7..a1cd108 100644 --- a/odb/pgsql/polymorphic-object-result.hxx +++ b/odb/pgsql/polymorphic-object-result.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/polymorphic-object-result.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_POLYMORPHIC_OBJECT_RESULT_HXX diff --git a/odb/pgsql/polymorphic-object-result.txx b/odb/pgsql/polymorphic-object-result.txx index c556a16..bad2091 100644 --- a/odb/pgsql/polymorphic-object-result.txx +++ b/odb/pgsql/polymorphic-object-result.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/polymorphic-object-result.txx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cassert> diff --git a/odb/pgsql/polymorphic-object-statements.hxx b/odb/pgsql/polymorphic-object-statements.hxx index 44839b6..717410a 100644 --- a/odb/pgsql/polymorphic-object-statements.hxx +++ b/odb/pgsql/polymorphic-object-statements.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/polymorphic-object-statements.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_POLYMORPHIC_OBJECT_STATEMENTS_HXX diff --git a/odb/pgsql/polymorphic-object-statements.txx b/odb/pgsql/polymorphic-object-statements.txx index ae1cc63..8472fca 100644 --- a/odb/pgsql/polymorphic-object-statements.txx +++ b/odb/pgsql/polymorphic-object-statements.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/polymorphic-object-statements.txx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cstring> // std::memset @@ -130,7 +129,7 @@ namespace odb root_type& robj, const schema_version_migration* svm) { - connection_type& conn (transaction::current ().connection ()); + connection_type& conn (transaction::current ().connection (db)); polymorphic_derived_object_statements& sts ( conn.statement_cache ().find_object<object_type> ()); root_statements_type& rsts (sts.root_statements ()); diff --git a/odb/pgsql/prepared-query.cxx b/odb/pgsql/prepared-query.cxx index 016652b..a6d783c 100644 --- a/odb/pgsql/prepared-query.cxx +++ b/odb/pgsql/prepared-query.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/prepared-query.cxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/pgsql/prepared-query.hxx> diff --git a/odb/pgsql/prepared-query.hxx b/odb/pgsql/prepared-query.hxx index b103d39..3622226 100644 --- a/odb/pgsql/prepared-query.hxx +++ b/odb/pgsql/prepared-query.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/prepared-query.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_PREPARED_QUERY_HXX diff --git a/odb/pgsql/query-const-expr.cxx b/odb/pgsql/query-const-expr.cxx index 3aa5101..c910620 100644 --- a/odb/pgsql/query-const-expr.cxx +++ b/odb/pgsql/query-const-expr.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/query-const-expr.cxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/pgsql/query.hxx> diff --git a/odb/pgsql/query-dynamic.cxx b/odb/pgsql/query-dynamic.cxx index 2ced689..ebd62de 100644 --- a/odb/pgsql/query-dynamic.cxx +++ b/odb/pgsql/query-dynamic.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/query-dynamic.cxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cstddef> // std::size_t diff --git a/odb/pgsql/query-dynamic.hxx b/odb/pgsql/query-dynamic.hxx index 71f8206..df87519 100644 --- a/odb/pgsql/query-dynamic.hxx +++ b/odb/pgsql/query-dynamic.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/query-dynamic.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_QUERY_DYNAMIC_HXX diff --git a/odb/pgsql/query-dynamic.ixx b/odb/pgsql/query-dynamic.ixx index 7b2de77..016d213 100644 --- a/odb/pgsql/query-dynamic.ixx +++ b/odb/pgsql/query-dynamic.ixx @@ -1,5 +1,4 @@ // file : odb/pgsql/query-dynamic.ixx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file namespace odb diff --git a/odb/pgsql/query-dynamic.txx b/odb/pgsql/query-dynamic.txx index 90da968..7cfaf63 100644 --- a/odb/pgsql/query-dynamic.txx +++ b/odb/pgsql/query-dynamic.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/query-dynamic.txx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file namespace odb diff --git a/odb/pgsql/query.cxx b/odb/pgsql/query.cxx index c1b9aee..b096c97 100644 --- a/odb/pgsql/query.cxx +++ b/odb/pgsql/query.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/query.cxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cstddef> // std::size_t diff --git a/odb/pgsql/query.hxx b/odb/pgsql/query.hxx index d880111..42182d6 100644 --- a/odb/pgsql/query.hxx +++ b/odb/pgsql/query.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/query.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_QUERY_HXX @@ -149,13 +148,14 @@ namespace odb kind_bool }; - clause_part (kind_type k): kind (k) {} - clause_part (kind_type k, const std::string& p): kind (k), part (p) {} + 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 = false; + bool bool_part; }; query_base () @@ -1671,7 +1671,7 @@ namespace odb bind (bind_type* b) { b->type = bind::numeric; - b->buffer = buffer_.data (); + b->buffer = buffer_.data_ptr (); b->capacity = buffer_.capacity (); b->size = &size_; } @@ -1836,7 +1836,7 @@ namespace odb bind (bind_type* b) { b->type = bind::text; - b->buffer = buffer_.data (); + b->buffer = buffer_.data_ptr (); b->capacity = buffer_.capacity (); b->size = &size_; } @@ -1881,7 +1881,7 @@ namespace odb bind (bind_type* b) { b->type = bind::bytea; - b->buffer = buffer_.data (); + b->buffer = buffer_.data_ptr (); b->capacity = buffer_.capacity (); b->size = &size_; } @@ -1926,7 +1926,7 @@ namespace odb bind (bind_type* b) { b->type = bind::bit; - b->buffer = buffer_.data (); + b->buffer = buffer_.data_ptr (); b->capacity = buffer_.capacity (); b->size = &size_; } @@ -1970,7 +1970,7 @@ namespace odb bind (bind_type* b) { b->type = bind::varbit; - b->buffer = buffer_.data (); + b->buffer = buffer_.data_ptr (); b->capacity = buffer_.capacity (); b->size = &size_; } diff --git a/odb/pgsql/query.ixx b/odb/pgsql/query.ixx index c8bf121..826b4ab 100644 --- a/odb/pgsql/query.ixx +++ b/odb/pgsql/query.ixx @@ -1,5 +1,4 @@ // file : odb/pgsql/query.ixx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file namespace odb diff --git a/odb/pgsql/query.txx b/odb/pgsql/query.txx index ad2ffe4..44dae30 100644 --- a/odb/pgsql/query.txx +++ b/odb/pgsql/query.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/query.txx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file namespace odb diff --git a/odb/pgsql/section-statements.hxx b/odb/pgsql/section-statements.hxx index 74dd35f..e40b282 100644 --- a/odb/pgsql/section-statements.hxx +++ b/odb/pgsql/section-statements.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/section-statements.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_SECTION_STATEMENTS_HXX diff --git a/odb/pgsql/section-statements.txx b/odb/pgsql/section-statements.txx index 5a081de..55f4093 100644 --- a/odb/pgsql/section-statements.txx +++ b/odb/pgsql/section-statements.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/section-statements.txx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cstring> // std::memset diff --git a/odb/pgsql/simple-object-result.hxx b/odb/pgsql/simple-object-result.hxx index 591c968..7472cbe 100644 --- a/odb/pgsql/simple-object-result.hxx +++ b/odb/pgsql/simple-object-result.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/simple-object-result.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_SIMPLE_OBJECT_RESULT_HXX diff --git a/odb/pgsql/simple-object-result.txx b/odb/pgsql/simple-object-result.txx index 949bfc5..c14d64b 100644 --- a/odb/pgsql/simple-object-result.txx +++ b/odb/pgsql/simple-object-result.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/simple-object-result.txx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cassert> diff --git a/odb/pgsql/simple-object-statements.cxx b/odb/pgsql/simple-object-statements.cxx index b7c926d..432f990 100644 --- a/odb/pgsql/simple-object-statements.cxx +++ b/odb/pgsql/simple-object-statements.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/simple-object-statements.cxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/pgsql/simple-object-statements.hxx> diff --git a/odb/pgsql/simple-object-statements.hxx b/odb/pgsql/simple-object-statements.hxx index fc845d4..086ef5f 100644 --- a/odb/pgsql/simple-object-statements.hxx +++ b/odb/pgsql/simple-object-statements.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/simple-object-statements.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_SIMPLE_OBJECT_STATEMENTS_HXX @@ -168,7 +167,8 @@ namespace odb typedef T object_type; typedef object_traits_impl<object_type, id_pgsql> object_traits; - optimistic_data (bind*, char** nv, int* nl, int* nf); + optimistic_data (bind*, char** nv, int* nl, int* nf, + std::size_t skip, unsigned long long* status); binding* id_image_binding () {return &id_image_binding_;} @@ -191,7 +191,8 @@ namespace odb template <typename T> struct optimistic_data<T, false> { - optimistic_data (bind*, char**, int*, int*) {} + optimistic_data (bind*, char**, int*, int*, + std::size_t, unsigned long long*) {} binding* id_image_binding () {return 0;} @@ -302,7 +303,7 @@ namespace odb // Object image. // image_type& - image () {return image_;} + image (std::size_t i = 0) {return images_[i].obj;} // Insert binding. // @@ -349,7 +350,7 @@ namespace odb // Object id image and binding. // id_image_type& - id_image () {return id_image_;} + id_image (std::size_t i = 0) {return images_[i].id;} std::size_t id_image_version () const {return id_image_version_;} @@ -472,8 +473,8 @@ namespace odb { return extra_statement_cache_.get ( conn_, - image_, - id_image_, + images_[0].obj, + images_[0].id, id_image_binding_, od_.id_image_binding (), id_image_native_binding_, @@ -528,7 +529,18 @@ namespace odb image_type, id_image_type> extra_statement_cache_; - image_type image_; + // 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]; + unsigned long long status_[object_traits::batch]; // Select binding. // @@ -575,7 +587,6 @@ namespace odb // Id image binding (only used as a parameter). Uses the suffix in // the update bind. // - id_image_type id_image_; std::size_t id_image_version_; binding id_image_binding_; native_binding id_image_native_binding_; diff --git a/odb/pgsql/simple-object-statements.ixx b/odb/pgsql/simple-object-statements.ixx index 5a5fe89..fbb2775 100644 --- a/odb/pgsql/simple-object-statements.ixx +++ b/odb/pgsql/simple-object-statements.ixx @@ -1,5 +1,4 @@ // file : odb/pgsql/simple-object-statements.ixx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file namespace odb diff --git a/odb/pgsql/simple-object-statements.txx b/odb/pgsql/simple-object-statements.txx index 42a14b0..bb47b43 100644 --- a/odb/pgsql/simple-object-statements.txx +++ b/odb/pgsql/simple-object-statements.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/simple-object-statements.txx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cstring> // std::memset @@ -20,11 +19,15 @@ namespace odb template <typename T> optimistic_data<T, true>:: - optimistic_data (bind* b, char** nv, int* nl, int* nf) + optimistic_data (bind* b, char** nv, int* nl, int* nf, + std::size_t skip, unsigned long long* status) : id_image_binding_ ( b, object_traits::id_column_count + - object_traits::managed_optimistic_column_count), + object_traits::managed_optimistic_column_count, + object_traits::batch, + skip, + status), id_image_native_binding_ ( nv, nl, nf, object_traits::id_column_count + @@ -49,7 +52,11 @@ namespace odb // select select_image_binding_ (select_image_bind_, select_column_count), // insert - insert_image_binding_ (insert_image_bind_, insert_column_count), + insert_image_binding_ (insert_image_bind_, + insert_column_count, + object_traits::batch, + sizeof (images), + status_), insert_image_native_binding_ (insert_image_values_, insert_image_lengths_, insert_image_formats_, @@ -57,7 +64,10 @@ namespace odb // update update_image_binding_ (update_image_bind_, update_column_count + id_column_count + - managed_optimistic_column_count), + managed_optimistic_column_count, + object_traits::batch, + sizeof (images), + status_), update_image_native_binding_ (update_image_values_, update_image_lengths_, update_image_formats_, @@ -65,7 +75,10 @@ namespace odb managed_optimistic_column_count), // id id_image_binding_ (update_image_bind_ + update_column_count, - id_column_count), + id_column_count, + object_traits::batch, + sizeof (images), + status_), id_image_native_binding_ ( update_image_values_ + update_column_count, update_image_lengths_ + update_column_count, @@ -75,15 +88,19 @@ namespace odb od_ (update_image_bind_ + update_column_count, update_image_values_ + update_column_count, update_image_lengths_ + update_column_count, - update_image_formats_ + update_column_count) + update_image_formats_ + update_column_count, + sizeof (images), + status_) { - image_.version = 0; + // 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; id_image_version_ = 0; std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_)); diff --git a/odb/pgsql/statement-cache.hxx b/odb/pgsql/statement-cache.hxx index c22734b..9417949 100644 --- a/odb/pgsql/statement-cache.hxx +++ b/odb/pgsql/statement-cache.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/statement-cache.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_STATEMENT_CACHE_HXX diff --git a/odb/pgsql/statement-cache.txx b/odb/pgsql/statement-cache.txx index f46d784..488ba2c 100644 --- a/odb/pgsql/statement-cache.txx +++ b/odb/pgsql/statement-cache.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/statement-cache.txx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/pgsql/database.hxx> diff --git a/odb/pgsql/statement.cxx b/odb/pgsql/statement.cxx index 377dc60..8574c37 100644 --- a/odb/pgsql/statement.cxx +++ b/odb/pgsql/statement.cxx @@ -1,17 +1,32 @@ // file : odb/pgsql/statement.cxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file -#include <cstdlib> // std::atol -#include <cassert> -#include <sstream> // istringstream +#include <odb/details/config.hxx> // ODB_CXX11 #include <libpq-fe.h> +#ifdef LIBPQ_HAS_PIPELINING +# ifndef _WIN32 +# include <errno.h> +# include <sys/select.h> +# endif +#endif + +#include <cstring> // strcmp +#include <utility> // pair +#include <cassert> + +#ifdef ODB_CXX11 +# include <cstdlib> // strtoull +#else +# include <sstream> // istringstream +#endif + #include <odb/tracer.hxx> #include <odb/pgsql/pgsql-oid.hxx> #include <odb/pgsql/statement.hxx> +#include <odb/pgsql/exceptions.hxx> #include <odb/pgsql/connection.hxx> #include <odb/pgsql/transaction.hxx> #include <odb/pgsql/auto-handle.hxx> @@ -37,11 +52,12 @@ namespace odb count = static_cast<unsigned long long> (s[0] - '0'); else { - // @@ Using stringstream conversion for now. See if we can optimize - // this (atoll possibly, even though it is not standard). - // +#ifdef ODB_CXX11 + count = strtoull (s, 0, 10); +#else istringstream ss (s); ss >> count; +#endif } return count; @@ -257,30 +273,39 @@ namespace odb return text_; } + template <typename T> + static inline T* + offset (T* base, size_t count, size_t size) + { + return reinterpret_cast<T*> ( + reinterpret_cast<char*> (base) + count * size); + } + void statement:: - bind_param (native_binding& n, const binding& b) + bind_param (native_binding& ns, const binding& bs, size_t pos) { - assert (n.count == b.count); + assert (ns.count == bs.count); - for (size_t i (0); i < n.count; ++i) + for (size_t i (0); i < ns.count; ++i) { - const bind& current_bind (b.bind[i]); + const bind& b (bs.bind[i]); - n.formats[i] = 1; + ns.formats[i] = 1; - if (current_bind.buffer == 0 || // Skip NULL entries. - (current_bind.is_null != 0 && *current_bind.is_null)) + bool* n (b.is_null != 0 ? offset (b.is_null, pos, bs.skip) : 0); + + if ((n != 0 && *n) || b.buffer == 0) // Handle NULL entries. { - n.values[i] = 0; - n.lengths[i] = 0; + ns.values[i] = 0; + ns.lengths[i] = 0; continue; } - n.values[i] = static_cast<char*> (current_bind.buffer); + ns.values[i] = static_cast<char*> (offset (b.buffer, pos, bs.skip)); size_t l (0); - switch (current_bind.type) + switch (b.type) { case bind::boolean_: { @@ -326,10 +351,18 @@ namespace odb case bind::numeric: case bind::text: case bind::bytea: - case bind::bit: case bind::varbit: { - l = *current_bind.size; + // In this case b.buffer is a pointer to pointer to buffer so we + // need to chase one level. + // + ns.values[i] = static_cast<char*> ( + *reinterpret_cast<void**> (ns.values[i])); + } + // Fall through. + case bind::bit: + { + l = *offset (b.size, pos, bs.skip); break; } case bind::uuid: @@ -341,54 +374,61 @@ namespace odb } } - n.lengths[i] = static_cast<int> (l); + ns.lengths[i] = static_cast<int> (l); } } bool statement:: - bind_result (bind* p, - size_t count, + bind_result (const binding& bs, PGresult* result, size_t row, - bool truncated) + bool truncated, + size_t pos) { bool r (true); int col_count (PQnfields (result)); int col (0); - for (size_t i (0); i != count && col != col_count; ++i) + for (size_t i (0); i != bs.count && col != col_count; ++i) { - const bind& b (p[i]); + const bind& b (bs.bind[i]); if (b.buffer == 0) // Skip NULL entries. continue; int c (col++); - if (truncated && (b.truncated == 0 || !*b.truncated)) - continue; + { + bool* t (b.truncated != 0 ? offset (b.truncated, pos, bs.skip) : 0); - if (b.truncated != 0) - *b.truncated = false; + if (truncated && (t == 0 || !*t)) + continue; + + if (t != 0) + *t = false; + } // Check for NULL unless we are reloading a truncated result. // if (!truncated) { - *b.is_null = PQgetisnull (result, static_cast<int> (row), c) == 1; + bool* n (offset (b.is_null, pos, bs.skip)); + + *n = PQgetisnull (result, static_cast<int> (row), c) == 1; - if (*b.is_null) + if (*n) continue; } + void* buf (offset (b.buffer, pos, bs.skip)); + const char* v (PQgetvalue (result, static_cast<int> (row), c)); switch (b.type) { case bind::boolean_: { - *static_cast<bool*> (b.buffer) = - *reinterpret_cast<const bool*> (v); + *static_cast<bool*> (buf) = *reinterpret_cast<const bool*> (v); break; } case bind::smallint: @@ -431,19 +471,19 @@ namespace odb { case bind::smallint: { - *static_cast<short*> (b.buffer) = + *static_cast<short*> (buf) = endian_traits::hton (static_cast<short> (i)); break; } case bind::integer: { - *static_cast<int*> (b.buffer) = + *static_cast<int*> (buf) = endian_traits::hton (static_cast<int> (i)); break; } case bind::bigint: { - *static_cast<long long*> (b.buffer) = endian_traits::hton (i); + *static_cast<long long*> (buf) = endian_traits::hton (i); break; } default: @@ -454,25 +494,23 @@ namespace odb } case bind::real: { - *static_cast<float*> (b.buffer) = - *reinterpret_cast<const float*> (v); + *static_cast<float*> (buf) = *reinterpret_cast<const float*> (v); break; } case bind::double_: { - *static_cast<double*> (b.buffer) = - *reinterpret_cast<const double*> (v); + *static_cast<double*> (buf) = *reinterpret_cast<const double*> (v); break; } case bind::date: { - *static_cast<int*> (b.buffer) = *reinterpret_cast<const int*> (v); + *static_cast<int*> (buf) = *reinterpret_cast<const int*> (v); break; } case bind::time: case bind::timestamp: { - *static_cast<long long*> (b.buffer) = + *static_cast<long long*> (buf) = *reinterpret_cast<const long long*> (v); break; } @@ -482,24 +520,37 @@ namespace odb case bind::bit: case bind::varbit: { + // Currently this is neither supported (due to capacity) nor used + // in batches. + // +#ifdef LIBPGSQL_EXTRA_CHECKS + assert (pos == 0); +#endif + *b.size = static_cast<size_t> ( PQgetlength (result, static_cast<int> (row), c)); - if (b.capacity < *b.size) - { - if (b.truncated) - *b.truncated = true; + if (b.capacity < *b.size) + { + if (b.truncated) + *b.truncated = true; - r = false; - continue; - } + r = false; + continue; + } + + // In these cases b.buffer is a pointer to pointer to buffer so we + // need to chase one level. + // + if (b.type != bind::bit) + buf = *static_cast<void**> (buf); - memcpy (b.buffer, v, *b.size); - break; + memcpy (buf, v, *b.size); + break; } case bind::uuid: { - memcpy (b.buffer, v, 16); + memcpy (buf, v, 16); break; } } @@ -515,6 +566,388 @@ namespace odb return r; } +#if defined(LIBPQ_HAS_PIPELINING) && !defined(_WIN32) + + // Note that this function always marks the connection as failed. + // + static void + translate_connection_error (connection& conn) + { + const char* m (PQerrorMessage (conn.handle ())); + + if (PQstatus (conn.handle ()) == CONNECTION_BAD) + { + conn.mark_failed (); + throw connection_lost (); + } + else + { + conn.mark_failed (); + throw database_exception (m != 0 ? m : "bad connection state"); + } + } + + // A RAII object for PGconn's non-blocking pipeline mode. + // + struct pipeline + { + connection& conn; + int sock; + + explicit + pipeline (connection& c) + : conn (c) + { + PGconn* ch (conn.handle ()); + + if ((sock = PQsocket (ch)) == -1 || + PQsetnonblocking (ch, 1) == -1 || + PQenterPipelineMode (ch) == 0) + { + translate_connection_error (conn); + } + } + + void + close (bool throw_ = true) + { + if (!conn.failed ()) + { + PGconn* ch (conn.handle ()); + + if (PQexitPipelineMode (ch) == 0 || + PQsetnonblocking (ch, 0) == -1) + { + if (throw_) + translate_connection_error (conn); + else + conn.mark_failed (); + } + } + } + + ~pipeline () + { + close (false); + } + + pair<bool /* read */, bool /* write */> + wait (bool write, bool throw_ = true) + { + fd_set wds; + fd_set rds; + + for (;;) + { + if (write) + { + FD_ZERO (&wds); + FD_SET (sock, &wds); + } + + FD_ZERO (&rds); + FD_SET (sock, &rds); + + if (select (sock + 1, &rds, write ? &wds : 0, 0, 0) != -1) + break; + + if (errno != EINTR) + { + if (throw_) + translate_connection_error (conn); + else + { + conn.mark_failed (); + return pair<bool, bool> (false, false); + } + } + } + + return pair<bool, bool> (FD_ISSET (sock, &rds), + write && FD_ISSET (sock, &wds)); + } + }; + + // A RAII object for recovering from an error in a pipeline. + // + // Specifically, it reads and discards results until reaching + // PGRES_PIPELINE_SYNC. + // + struct pipeline_recovery + { + pipeline_recovery (pipeline& pl, bool wdone, bool sync) + : pl_ (&pl), wdone_ (wdone), sync_ (sync) + { + } + + ~pipeline_recovery () + { + if (pl_ != 0 && !pl_->conn.failed ()) + { + PGconn* ch (pl_->conn.handle ()); + + // This code runs as part of stack unwinding caused by an exception + // so if we encounter an error, we "upgrade" the existing exception + // by marking the connection as failed. + // + // The rest is essentially a special version of execute() below. + // + // Note that on the first iteration we may still have results from + // the previous call to PQconsumeInput() (and these results may + // be the entire outstanding sequence, in which case calling wait() + // will block indefinitely). + // + for (bool first (true);; first = false) + { + if (sync_) + { + assert (!wdone_); + + if (PQpipelineSync (ch) == 0) + break; + + sync_ = false; + } + + pair<bool, bool> r (false, false); + + if (!first) + { + r = pl_->wait (!wdone_); + if (!r.first && !r.second) + break; + } + + if (r.first /* read */ || first) + { + if (r.first && PQconsumeInput (ch) == 0) + break; + + while (PQisBusy (ch) == 0) + { + auto_handle<PGresult> res (PQgetResult (ch)); + + // We should only get NULLs as well as PGRES_PIPELINE_ABORTED + // finished with PGRES_PIPELINE_SYNC. + // + if (res != 0) + { + ExecStatusType stat (PQresultStatus (res)); + + if (stat == PGRES_PIPELINE_SYNC) + return; + + assert (stat == PGRES_PIPELINE_ABORTED); + } + } + } + + if (r.second /* write */) + { + int r (PQflush (ch)); + if (r == -1) + break; + + if (r == 0) + wdone_ = true; + } + } + + pl_->conn.mark_failed (); + } + } + + void + cancel () + { + pl_ = 0; + } + + private: + pipeline* pl_; + bool wdone_; + bool sync_; + }; + + size_t statement:: + execute (const binding& param, + native_binding& native_param, + size_t n, + multiple_exceptions& mex, + bool (*process) (size_t, PGresult*, bool, void*), + void* data) + { + size_t i (0); // Parameter set being attempted. + mex.current (i); + + PGconn* ch (conn_.handle ()); + + pipeline pl (conn_); + + // True if we've written and read everything, respectively. + // + bool wdone (false), rdone (false); + + for (size_t wn (0), rn (0); !rdone; ) + { + // Note that there is a special version of this code above in + // ~pipeline_recovery(). + // + pair<bool, bool> r (pl.wait (!wdone)); + + // Note that once we start the pipeline, any call that may throw + // without marking the connection as failed should be guarded by + // pipeline_recovery. + + // Try to minimize the chance of blocking the server by first + // processing the result and then sending more queries. + // + if (r.first /* read */) + { + if (PQconsumeInput (ch) == 0) + translate_connection_error (conn_); + + // Note that PQisBusy() will return 0 (and subsequent PQgetResult() + // -- NULL) if we have consumed all the results for the queries that + // we have sent so far. Thus the (wn > rn) condition. Note that for + // this to work correctly we have to count the PQpipelineSync() call + // below as one of the queries (since it has a separate result). + // + while (wn > rn && PQisBusy (ch) == 0) + { + auto_handle<PGresult> res (PQgetResult (ch)); + + ExecStatusType stat (PGRES_FATAL_ERROR); + bool gr (is_good_result (res, &stat)); + + if (stat == PGRES_PIPELINE_SYNC) + { + assert (wdone && rn == n); + rdone = true; + break; + } + + assert (rn != n); + ++rn; + + if (stat != PGRES_PIPELINE_ABORTED) + { + // translate_error() may throw an exception (e.g., deadlock) + // without marking the connection as failed. + // + { + pipeline_recovery plr (pl, wdone, wn < n); + + if (!process (i, res, gr, data)) + translate_error (conn_, res, i, &mex); + + plr.cancel (); + } + + mex.attempted (++i); + mex.current (i); + } + else + { + // Should we treat PGRES_PIPELINE_ABORTED entries as attempted + // or not? While we did issue PQsendQueryPrepared() for them, + // the server tells us that it did not attemp to execute them. + // So it feels like they should not be treated as attempted. + // + // Note that for this to fit into out multiple_exceptions model, + // such an incomplete batch should be fatal (otherwise we could + // end up with unattempted "holes"). This is currently the case + // for errors handled by translate_error() but not necessarily + // the case for those handled by the process function (e.g., + // duplicate id handled by process_insert_result() below). So in + // a somewhat hackish way we assume the error (e.g., duplicate + // id) will always be translated to an exception and pre-mark + // multiple_exceptions as fatal. + // + mex.fatal (true); + } + + // We get a NULL result after each query result. + // + { + PGresult* end (PQgetResult (ch)); + assert (end == 0); + } + } + } + + if (r.second /* write */) + { + // Send queries until we get blocked (write-biased). This feels like + // a better overall strategy to keep the server busy compared to + // sending one query at a time and then re-checking if there is + // anything to read because the results of INSERT/UPDATE/DELETE are + // presumably small and quite a few of them can get buffered before + // the server gets blocked. + // + for (;;) + { + if (wn < n) + { + bind_param (native_param, param, wn); + + if (PQsendQueryPrepared (ch, + name_, + static_cast<int> (native_param.count), + native_param.values, + native_param.lengths, + native_param.formats, + 1) == 0) + translate_connection_error (conn_); + + if (++wn == n) + { + if (PQpipelineSync (ch) == 0) + translate_connection_error (conn_); + + // Count as one of the queries since it has a separate result. + // + ++wn; + } + } + + // PQflush() result: + // + // 0 -- success (queue is now empty) + // 1 -- blocked + // -1 -- error + // + int r (PQflush (ch)); + if (r == -1) + translate_connection_error (conn_); + + if (r == 0) + { + if (wn < n) + { + // If we continue here, then we are write-biased. And if we + // break, then we are read-biased. + // +#ifdef LIBPGSQL_READ_BIASED + break; +#else + continue; +#endif + } + + wdone = true; + } + + break; // Blocked or done. + } + } + } + + pl.close (); + return i; + } +#endif + // // select_statement // @@ -690,10 +1123,7 @@ namespace odb return no_data; assert (current_row_ > 0); - return bind_result (result_.bind, - result_.count, - handle_, - current_row_ - 1) + return bind_result (result_, handle_, current_row_ - 1) ? success : truncated; } @@ -704,11 +1134,7 @@ namespace odb assert (current_row_ > 0); assert (current_row_ <= row_count_); - if (!bind_result (result_.bind, - result_.count, - handle_, - current_row_ - 1, - true)) + if (!bind_result (result_, handle_, current_row_ - 1, true)) assert (false); } @@ -739,6 +1165,8 @@ namespace odb native_param_ (native_param), returning_ (returning) { + if (returning_ != 0) + assert (returning_->count == 1); } insert_statement:: @@ -760,6 +1188,8 @@ namespace odb native_param_ (native_param), returning_ (returning) { + if (returning_ != 0) + assert (returning_->count == 1); } bool insert_statement:: @@ -793,9 +1223,9 @@ namespace odb // if (returning_ == 0 && stat == PGRES_FATAL_ERROR) { - string s (PQresultErrorField (h, PG_DIAG_SQLSTATE)); + const char* ss (PQresultErrorField (h, PG_DIAG_SQLSTATE)); - if (s == "23505") + if (ss != 0 && strcmp (ss, "23505") == 0) return false; } @@ -803,11 +1233,76 @@ namespace odb } if (returning_ != 0) - bind_result (returning_->bind, 1, h, 0, false); + bind_result (*returning_, h, 0); + + return true; + } + +#if defined(LIBPQ_HAS_PIPELINING) && !defined(_WIN32) + + struct insert_data + { + binding& param; + binding* returning; + }; + + static bool + process_insert_result (size_t i, PGresult* r, bool gr, void* data) + { + insert_data& d (*static_cast<insert_data*> (data)); + + unsigned long long& s (d.param.status[i]); + s = 1; + + if (gr) + { + // Note that the result can never be truncated. + // + if (d.returning != 0) + statement::bind_result (*d.returning, r, 0, false, i); + } + else + { + // An auto-assigned object id should never cause a duplicate + // primary key. + // + if (d.returning == 0 && + r != 0 && PQresultStatus (r) == PGRES_FATAL_ERROR) + { + // Note that statement::execute() assumes that this will eventually + // be translated to an entry in multiple_exceptions. + // + const char* ss (PQresultErrorField (r, PG_DIAG_SQLSTATE)); + + if (ss != 0 && strcmp (ss, "23505") == 0) + s = 0; + } + + if (s == 1) + return false; + } return true; } + size_t insert_statement:: + execute (size_t n, multiple_exceptions& mex) + { + { + odb::tracer* t; + if ((t = conn_.transaction_tracer ()) || + (t = conn_.tracer ()) || + (t = conn_.database ().tracer ())) + t->execute (conn_, *this); + } + + insert_data d {param_, returning_}; + + return statement::execute ( + param_, native_param_, n, mex, &process_insert_result, &d); + } +#endif + // // update_statement // @@ -882,6 +1377,43 @@ namespace odb return affected_row_count (h); } +#if defined(LIBPQ_HAS_PIPELINING) && !defined(_WIN32) + + static bool + process_update_result (size_t i, PGresult* r, bool gr, void* data) + { + binding& param (*static_cast<binding*> (data)); + + unsigned long long& s (param.status[i]); + + if (gr) + { + s = affected_row_count (r); + return true; + } + else + { + s = update_statement::result_unknown; + return false; + } + } + + size_t update_statement:: + execute (size_t n, multiple_exceptions& mex) + { + { + odb::tracer* t; + if ((t = conn_.transaction_tracer ()) || + (t = conn_.tracer ()) || + (t = conn_.database ().tracer ())) + t->execute (conn_, *this); + } + + return statement::execute ( + param_, native_param_, n, mex, &process_update_result, ¶m_); + } +#endif + // // delete_statement // @@ -970,5 +1502,44 @@ namespace odb return affected_row_count (h); } + +#if defined(LIBPQ_HAS_PIPELINING) && !defined(_WIN32) + + static bool + process_delete_result (size_t i, PGresult* r, bool gr, void* data) + { + binding& param (*static_cast<binding*> (data)); + + unsigned long long& s (param.status[i]); + + if (gr) + { + s = affected_row_count (r); + return true; + } + else + { + s = delete_statement::result_unknown; + return false; + } + } + + size_t delete_statement:: + execute (size_t n, multiple_exceptions& mex) + { + assert (param_ != 0); + + { + odb::tracer* t; + if ((t = conn_.transaction_tracer ()) || + (t = conn_.tracer ()) || + (t = conn_.database ().tracer ())) + t->execute (conn_, *this); + } + + return statement::execute ( + *param_, native_param_, n, mex, &process_delete_result, param_); + } +#endif } } diff --git a/odb/pgsql/statement.hxx b/odb/pgsql/statement.hxx index e5c084d..139d2d6 100644 --- a/odb/pgsql/statement.hxx +++ b/odb/pgsql/statement.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/statement.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_STATEMENT_HXX @@ -64,22 +63,24 @@ namespace odb void deallocate (); - // Adapt an ODB binding to a native PostgreSQL parameter binding. + // Adapt an ODB binding to a native PostgreSQL parameter binding. If pos + // is not 0, then bind the parameter set at this position in a batch. // static void - bind_param (native_binding&, const binding&); + bind_param (native_binding&, const binding&, std::size_t pos = 0); // Populate an ODB binding given a PostgreSQL result. If the truncated // argument is true, then only truncated columns are extracted. Return // true if all the data was extracted successfully and false if one or - // more columns were truncated. + // more columns were truncated. If pos is not 0, then populate the + // parameter set at this position in a batch. // static bool - bind_result (bind*, - std::size_t count, + bind_result (const binding&, PGresult*, std::size_t row, - bool truncated = false); + bool truncated = false, + std::size_t pos = 0); protected: // We keep two versions to take advantage of std::string COW. @@ -103,6 +104,16 @@ namespace odb const Oid* types, std::size_t types_count); + // Bulk execute implementation. + // + std::size_t + execute (const binding& param, + native_binding& native_param, + std::size_t n, + multiple_exceptions&, + bool (*process) (size_t i, PGresult*, bool good, void* data), + void* data); + private: void init (statement_kind, @@ -297,6 +308,20 @@ namespace odb bool execute (); + // Return the number of parameter sets (out of n) that were attempted. + // + std::size_t + execute (std::size_t n, multiple_exceptions&); + + // Return true if successful and false if this row is a duplicate. + // All other errors are reported via exceptions. + // + bool + result (std::size_t i) + { + return param_.status[i] != 0; + } + private: insert_statement (const insert_statement&); insert_statement& operator= (const insert_statement&); @@ -335,6 +360,22 @@ namespace odb unsigned long long execute (); + // Return the number of parameter sets (out of n) that were attempted. + // + std::size_t + execute (std::size_t n, multiple_exceptions&); + + // Return the number of rows affected (updated) by the parameter + // set. All errors are reported by throwing exceptions. + // + static const unsigned long long result_unknown = ~0ULL; + + unsigned long long + result (std::size_t i) + { + return param_.status[i]; + } + private: update_statement (const update_statement&); update_statement& operator= (const update_statement&); @@ -377,6 +418,22 @@ namespace odb unsigned long long execute (); + // Return the number of parameter sets (out of n) that were attempted. + // + std::size_t + execute (std::size_t n, multiple_exceptions&); + + // Return the number of rows affected (deleted) by the parameter + // set. All errors are reported by throwing exceptions. + // + static const unsigned long long result_unknown = ~0ULL; + + unsigned long long + result (std::size_t i) + { + return param_->status[i]; + } + private: delete_statement (const delete_statement&); delete_statement& operator= (const delete_statement&); diff --git a/odb/pgsql/statements-base.cxx b/odb/pgsql/statements-base.cxx index 2145c02..0e72555 100644 --- a/odb/pgsql/statements-base.cxx +++ b/odb/pgsql/statements-base.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/statements-base.cxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/pgsql/statements-base.hxx> diff --git a/odb/pgsql/statements-base.hxx b/odb/pgsql/statements-base.hxx index 3d900cb..8b45bdc 100644 --- a/odb/pgsql/statements-base.hxx +++ b/odb/pgsql/statements-base.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/statements-base.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_STATEMENTS_BASE_HXX diff --git a/odb/pgsql/tracer.cxx b/odb/pgsql/tracer.cxx index e7f0fbc..48e0cf8 100644 --- a/odb/pgsql/tracer.cxx +++ b/odb/pgsql/tracer.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/tracer.cxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/pgsql/tracer.hxx> diff --git a/odb/pgsql/tracer.hxx b/odb/pgsql/tracer.hxx index 80fc242..89cda1c 100644 --- a/odb/pgsql/tracer.hxx +++ b/odb/pgsql/tracer.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/tracer.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_TRACER_HXX diff --git a/odb/pgsql/traits-calls.hxx b/odb/pgsql/traits-calls.hxx index 78ea087..419c7b2 100644 --- a/odb/pgsql/traits-calls.hxx +++ b/odb/pgsql/traits-calls.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/traits-calls.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_TRAITS_CALLS_HXX diff --git a/odb/pgsql/traits.cxx b/odb/pgsql/traits.cxx index b729fd6..11a3a67 100644 --- a/odb/pgsql/traits.cxx +++ b/odb/pgsql/traits.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/traits.cxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/pgsql/traits.hxx> diff --git a/odb/pgsql/traits.hxx b/odb/pgsql/traits.hxx index 8bc5347..3d87033 100644 --- a/odb/pgsql/traits.hxx +++ b/odb/pgsql/traits.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/traits.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_TRAITS_HXX diff --git a/odb/pgsql/transaction-impl.cxx b/odb/pgsql/transaction-impl.cxx index d9ae2a6..012fe18 100644 --- a/odb/pgsql/transaction-impl.cxx +++ b/odb/pgsql/transaction-impl.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/transaction-impl.cxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cassert> diff --git a/odb/pgsql/transaction-impl.hxx b/odb/pgsql/transaction-impl.hxx index 90af9d0..5c93b0e 100644 --- a/odb/pgsql/transaction-impl.hxx +++ b/odb/pgsql/transaction-impl.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/transaction-impl.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_TRANSACTION_IMPL_HXX @@ -39,17 +38,12 @@ namespace odb virtual void rollback (); - connection_type& - connection (); - private: connection_ptr connection_; }; } } -#include <odb/pgsql/transaction-impl.ixx> - #include <odb/post.hxx> #endif // ODB_PGSQL_TRANSACTION_IMPL_HXX diff --git a/odb/pgsql/transaction-impl.ixx b/odb/pgsql/transaction-impl.ixx deleted file mode 100644 index 67c7e57..0000000 --- a/odb/pgsql/transaction-impl.ixx +++ /dev/null @@ -1,15 +0,0 @@ -// file : odb/pgsql/transaction-impl.ixx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -namespace odb -{ - namespace pgsql - { - inline transaction_impl::connection_type& transaction_impl:: - connection () - { - return *connection_; - } - } -} diff --git a/odb/pgsql/transaction.cxx b/odb/pgsql/transaction.cxx index c9410b2..3b32d80 100644 --- a/odb/pgsql/transaction.cxx +++ b/odb/pgsql/transaction.cxx @@ -1,5 +1,4 @@ // file : odb/pgsql/transaction.cxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cassert> diff --git a/odb/pgsql/transaction.hxx b/odb/pgsql/transaction.hxx index d6f87ca..e83c754 100644 --- a/odb/pgsql/transaction.hxx +++ b/odb/pgsql/transaction.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/transaction.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_TRANSACTION_HXX @@ -42,6 +41,9 @@ namespace odb connection_type& connection (); + connection_type& + connection (odb::database&); + // Return current transaction or throw if there is no transaction // in effect. // diff --git a/odb/pgsql/transaction.ixx b/odb/pgsql/transaction.ixx index 40313bc..31aa603 100644 --- a/odb/pgsql/transaction.ixx +++ b/odb/pgsql/transaction.ixx @@ -1,5 +1,4 @@ // file : odb/pgsql/transaction.ixx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/pgsql/database.hxx> @@ -40,7 +39,13 @@ namespace odb inline transaction::connection_type& transaction:: connection () { - return implementation ().connection (); + return static_cast<connection_type&> (odb::transaction::connection ()); + } + + inline transaction::connection_type& transaction:: + connection (odb::database& db) + { + return static_cast<connection_type&> (odb::transaction::connection (db)); } inline void transaction:: diff --git a/odb/pgsql/version-build2-stub.hxx b/odb/pgsql/version-build2-stub.hxx index bb9edc8..a99b093 100644 --- a/odb/pgsql/version-build2-stub.hxx +++ b/odb/pgsql/version-build2-stub.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/version-build2-stub.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/pgsql/version.hxx> diff --git a/odb/pgsql/version-build2.hxx.in b/odb/pgsql/version-build2.hxx.in index d33d1d5..ed4396b 100644 --- a/odb/pgsql/version-build2.hxx.in +++ b/odb/pgsql/version-build2.hxx.in @@ -1,5 +1,4 @@ // file : odb/pgsql/version-build2.hxx.in -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef LIBODB_PGSQL_VERSION // Note: using the version macro itself. diff --git a/odb/pgsql/version.hxx b/odb/pgsql/version.hxx index 78b9f79..e050de4 100644 --- a/odb/pgsql/version.hxx +++ b/odb/pgsql/version.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/version.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifdef LIBODB_PGSQL_BUILD2 @@ -33,15 +32,15 @@ // Check that we have compatible ODB version. // -#if ODB_VERSION != 20466 +#if ODB_VERSION != 20476 # error incompatible odb interface version detected #endif // libodb-pgsql version: odb interface version plus the bugfix // version. // -#define LIBODB_PGSQL_VERSION 2049966 -#define LIBODB_PGSQL_VERSION_STR "2.5.0-b.16" +#define LIBODB_PGSQL_VERSION 2049976 +#define LIBODB_PGSQL_VERSION_STR "2.5.0-b.26" #include <odb/post.hxx> diff --git a/odb/pgsql/view-result.hxx b/odb/pgsql/view-result.hxx index 819b8fb..f9acace 100644 --- a/odb/pgsql/view-result.hxx +++ b/odb/pgsql/view-result.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/view-result.hxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_VIEW_RESULT_HXX diff --git a/odb/pgsql/view-result.txx b/odb/pgsql/view-result.txx index eaf8969..980811a 100644 --- a/odb/pgsql/view-result.txx +++ b/odb/pgsql/view-result.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/view-result.txx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <odb/callback.hxx> diff --git a/odb/pgsql/view-statements.hxx b/odb/pgsql/view-statements.hxx index a512181..970e610 100644 --- a/odb/pgsql/view-statements.hxx +++ b/odb/pgsql/view-statements.hxx @@ -1,5 +1,4 @@ // file : odb/pgsql/view-statements.hxx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_VIEW_STATEMENTS_HXX diff --git a/odb/pgsql/view-statements.txx b/odb/pgsql/view-statements.txx index c8b1db7..afa2a49 100644 --- a/odb/pgsql/view-statements.txx +++ b/odb/pgsql/view-statements.txx @@ -1,5 +1,4 @@ // file : odb/pgsql/view-statements.txx -// copyright : Copyright (c) 2005-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #include <cstddef> // std::size_t diff --git a/repositories.manifest b/repositories.manifest index b4bccc3..4451c88 100644 --- a/repositories.manifest +++ b/repositories.manifest @@ -3,8 +3,12 @@ summary: PostgreSQL ODB runtime library repository : role: prerequisite -location: https://git.build2.org/packaging/postgresql/libpq.git##HEAD +location: https://git.build2.org/packaging/postgresql/postgresql.git##HEAD : role: prerequisite location: ../libodb.git##HEAD + +: +role: prerequisite +location: https://git.codesynthesis.com/cli/cli.git##HEAD diff --git a/tests/basics/buildfile b/tests/basics/buildfile index b47b13f..fccb243 100644 --- a/tests/basics/buildfile +++ b/tests/basics/buildfile @@ -1,5 +1,4 @@ # file : tests/basics/buildfile -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file import libs = libodb-pgsql%lib{odb-pgsql} diff --git a/tests/basics/driver.cxx b/tests/basics/driver.cxx index 287a52e..efd1985 100644 --- a/tests/basics/driver.cxx +++ b/tests/basics/driver.cxx @@ -1,5 +1,4 @@ // file : tests/basics/driver.cxx -// copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file // Basic test to make sure the library is usable. Functionality testing diff --git a/tests/build/bootstrap.build b/tests/build/bootstrap.build index c5c067b..6ee38db 100644 --- a/tests/build/bootstrap.build +++ b/tests/build/bootstrap.build @@ -1,5 +1,4 @@ # file : tests/build/bootstrap.build -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file project = # Unnamed subproject. diff --git a/tests/build/root.build b/tests/build/root.build index da6ff40..6c5a90b 100644 --- a/tests/build/root.build +++ b/tests/build/root.build @@ -1,5 +1,4 @@ # file : tests/build/root.build -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file cxx.std = latest diff --git a/tests/buildfile b/tests/buildfile index 3614001..57588a4 100644 --- a/tests/buildfile +++ b/tests/buildfile @@ -1,5 +1,4 @@ # file : tests/buildfile -# copyright : Copyright (c) 2009-2019 Code Synthesis Tools CC # license : GNU GPL v2; see accompanying LICENSE file ./: {*/ -build/} diff --git a/version b/version deleted file mode 100644 index dfe1a80..0000000 --- a/version +++ /dev/null @@ -1 +0,0 @@ -2.5.0-b.16 diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..6bc2f39 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +2.5.0-b.26 |