Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
dCache
cta
Commits
1015562f
Commit
1015562f
authored
Dec 02, 2019
by
Steven Murray
Browse files
Added unit-test insert_same_primary_twice
parent
b22d8865
Changes
7
Show whitespace changes
Inline
Side-by-side
common/CMakeLists.txt
View file @
1015562f
...
...
@@ -84,6 +84,7 @@ set (COMMON_LIB_SRC_FILES
exception/DatabaseCheckConstraintError.cpp
exception/DatabaseConstraintError.cpp
exception/DatabasePrimaryKeyError.cpp
exception/DatabaseUniqueError.cpp
exception/DismountFailed.cpp
exception/ForceDismountFailed.cpp
exception/Errnum.cpp
...
...
common/exception/DatabaseUniqueError.cpp
0 → 100644
View file @
1015562f
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include
"common/exception/DatabaseUniqueError.hpp"
namespace
cta
{
namespace
exception
{
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
DatabaseUniqueError
::
DatabaseUniqueError
(
const
std
::
string
&
context
,
const
bool
embedBacktrace
)
:
DatabaseConstraintError
(
context
,
embedBacktrace
)
{
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
DatabaseUniqueError
::~
DatabaseUniqueError
()
noexcept
{
}
}
// namespace exception
}
// namespace cta
common/exception/DatabaseUniqueError.hpp
0 → 100644
View file @
1015562f
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include
"common/exception/DatabaseConstraintError.hpp"
#include
<string>
namespace
cta
{
namespace
exception
{
/**
* A database constraint has been violated.
*/
class
DatabaseUniqueError
:
public
DatabaseConstraintError
{
public:
/**
* Constructor.
*
* @param context optional context string added to the message
* at initialisation time.
* @param embedBacktrace whether to embed a backtrace of where the
* exception was throw in the message
*/
DatabaseUniqueError
(
const
std
::
string
&
context
=
""
,
const
bool
embedBacktrace
=
true
);
/**
* Empty Destructor, explicitely non-throwing (needed for std::exception
* inheritance)
*/
~
DatabaseUniqueError
()
noexcept
override
;
};
// class DatabaseUniqueError
}
// namespace exception
}
// namespace cta
rdbms/StmtTest.cpp
View file @
1015562f
...
...
@@ -18,6 +18,7 @@
#include
"common/exception/DatabaseCheckConstraintError.hpp"
#include
"common/exception/DatabasePrimaryKeyError.hpp"
#include
"common/exception/DatabaseUniqueError.hpp"
#include
"common/exception/Exception.hpp"
#include
"common/make_unique.hpp"
#include
"common/utils/utils.hpp"
...
...
@@ -63,10 +64,12 @@ std::string cta_rdbms_StmtTest::getCreateStmtTestTableSql() {
try
{
std
::
string
sql
=
"CREATE TABLE STMT_TEST("
"
\n
"
" ID UINT64TYPE CONSTRAINT STMT_TEST_ID_NN NOT NULL,"
"
\n
"
" DOUBLE_COL FLOAT,"
"
\n
"
" UINT64_COL UINT64TYPE,"
"
\n
"
" STRING_COL VARCHAR(100),"
"
\n
"
" BOOL_COL CHAR(1) DEFAULT '0',"
"
\n
"
" CONSTRAINT STMT_TEST_PK PRIMARY KEY(ID),"
"
\n
"
" CONSTRAINT BOOL_COL_BOOL_CK CHECK(BOOL_COL IN ('0', '1'))"
"
\n
"
")"
;
...
...
@@ -127,10 +130,12 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindDouble) {
// Insert a row into the test table
{
const
char
*
const
sql
=
"INSERT INTO STMT_TEST("
"DOUBLE_COL) "
"VALUES("
":DOUBLE_COL)"
;
"INSERT INTO STMT_TEST("
"
\n
"
" ID,"
"
\n
"
" DOUBLE_COL)"
"
\n
"
"VALUES("
"
\n
"
" 1,"
"
\n
"
" :DOUBLE_COL)"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
stmt
.
bindDouble
(
":DOUBLE_COL"
,
insertValue
);
stmt
.
executeNonQuery
();
...
...
@@ -139,10 +144,10 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindDouble) {
// Select the row back from the table
{
const
char
*
const
sql
=
"SELECT
"
"
DOUBLE_COL AS DOUBLE_COL "
"FROM
"
"
STMT_TEST"
;
"SELECT
"
"
\n
"
"
DOUBLE_COL AS DOUBLE_COL
"
"
\n
"
"FROM
"
"
\n
"
"
STMT_TEST"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
auto
rset
=
stmt
.
executeQuery
();
ASSERT_TRUE
(
rset
.
next
());
...
...
@@ -166,10 +171,12 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindUint64) {
// Insert a row into the test table
{
const
char
*
const
sql
=
"INSERT INTO STMT_TEST("
"UINT64_COL) "
"VALUES("
":UINT64_COL)"
;
"INSERT INTO STMT_TEST("
"
\n
"
" ID,"
"
\n
"
" UINT64_COL) "
"
\n
"
"VALUES("
"
\n
"
" 1,"
"
\n
"
" :UINT64_COL)"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
stmt
.
bindDouble
(
":UINT64_COL"
,
insertValue
);
stmt
.
executeNonQuery
();
...
...
@@ -178,10 +185,10 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindUint64) {
// Select the row back from the table
{
const
char
*
const
sql
=
"SELECT
"
"
UINT64_COL AS UINT64_COL "
"FROM
"
"
STMT_TEST"
;
"SELECT
"
"
\n
"
"
UINT64_COL AS UINT64_COL
"
"
\n
"
"FROM
"
"
\n
"
"
STMT_TEST"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
auto
rset
=
stmt
.
executeQuery
();
ASSERT_TRUE
(
rset
.
next
());
...
...
@@ -204,10 +211,12 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindUint64_2_pow_64_minus_1) {
// Insert a row into the test table
{
const
char
*
const
sql
=
"INSERT INTO STMT_TEST("
"UINT64_COL) "
"VALUES("
":UINT64_COL)"
;
"INSERT INTO STMT_TEST("
"
\n
"
" ID,"
"
\n
"
" UINT64_COL)"
"
\n
"
"VALUES("
"
\n
"
" 1,"
"
\n
"
" :UINT64_COL)"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
stmt
.
bindUint64
(
":UINT64_COL"
,
insertValue
);
stmt
.
executeNonQuery
();
...
...
@@ -216,10 +225,10 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindUint64_2_pow_64_minus_1) {
// Select the row back from the table
{
const
char
*
const
sql
=
"SELECT
"
"
UINT64_COL AS UINT64_COL "
"FROM
"
"
STMT_TEST"
;
"SELECT
"
"
\n
"
"
UINT64_COL AS UINT64_COL
"
"
\n
"
"FROM
"
"
\n
"
"
STMT_TEST"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
auto
rset
=
stmt
.
executeQuery
();
ASSERT_TRUE
(
rset
.
next
());
...
...
@@ -242,10 +251,12 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindUint64_2_pow_64_minus_2) {
// Insert a row into the test table
{
const
char
*
const
sql
=
"INSERT INTO STMT_TEST("
"UINT64_COL) "
"VALUES("
":UINT64_COL)"
;
"INSERT INTO STMT_TEST("
"
\n
"
" ID,"
"
\n
"
" UINT64_COL)"
"
\n
"
"VALUES("
"
\n
"
" 1,"
"
\n
"
" :UINT64_COL)"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
stmt
.
bindUint64
(
":UINT64_COL"
,
insertValue
);
stmt
.
executeNonQuery
();
...
...
@@ -254,10 +265,10 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindUint64_2_pow_64_minus_2) {
// Select the row back from the table
{
const
char
*
const
sql
=
"SELECT
"
"
UINT64_COL AS UINT64_COL "
"FROM
"
"
STMT_TEST"
;
"SELECT
"
"
\n
"
"
UINT64_COL AS UINT64_COL
"
"
\n
"
"FROM
"
"
\n
"
"
STMT_TEST"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
auto
rset
=
stmt
.
executeQuery
();
ASSERT_TRUE
(
rset
.
next
());
...
...
@@ -280,10 +291,12 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindString) {
// Insert a row into the test table
{
const
char
*
const
sql
=
"INSERT INTO STMT_TEST("
"STRING_COL) "
"VALUES("
":STRING_COL)"
;
"INSERT INTO STMT_TEST("
"
\n
"
" ID,"
"
\n
"
" STRING_COL)"
"
\n
"
"VALUES("
"
\n
"
" 1,"
"
\n
"
" :STRING_COL)"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
stmt
.
bindString
(
":STRING_COL"
,
insertValue
);
stmt
.
executeNonQuery
();
...
...
@@ -292,10 +305,10 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindString) {
// Select the row back from the table
{
const
char
*
const
sql
=
"SELECT
"
"
STRING_COL AS STRING_COL "
"FROM
"
"
STMT_TEST"
;
"SELECT
"
"
\n
"
"
STRING_COL AS STRING_COL
"
"
\n
"
"FROM
"
"
\n
"
"
STMT_TEST"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
auto
rset
=
stmt
.
executeQuery
();
ASSERT_TRUE
(
rset
.
next
());
...
...
@@ -318,10 +331,12 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindBool_true) {
// Insert a row into the test table
{
const
char
*
const
sql
=
"INSERT INTO STMT_TEST("
"BOOL_COL) "
"VALUES("
":BOOL_COL)"
;
"INSERT INTO STMT_TEST("
"
\n
"
" ID,"
"
\n
"
" BOOL_COL)"
"
\n
"
"VALUES("
"
\n
"
" 1,"
"
\n
"
" :BOOL_COL)"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
stmt
.
bindBool
(
":BOOL_COL"
,
insertValue
);
stmt
.
executeNonQuery
();
...
...
@@ -330,10 +345,10 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindBool_true) {
// Select the row back from the table
{
const
char
*
const
sql
=
"SELECT
"
"
BOOL_COL AS BOOL_COL "
"FROM
"
"
STMT_TEST"
;
"SELECT
"
"
\n
"
"
BOOL_COL AS BOOL_COL
"
"
\n
"
"FROM
"
"
\n
"
"
STMT_TEST"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
auto
rset
=
stmt
.
executeQuery
();
ASSERT_TRUE
(
rset
.
next
());
...
...
@@ -356,10 +371,12 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindBool_false) {
// Insert a row into the test table
{
const
char
*
const
sql
=
"INSERT INTO STMT_TEST("
"BOOL_COL) "
"VALUES("
":BOOL_COL)"
;
"INSERT INTO STMT_TEST("
"
\n
"
" ID,"
"
\n
"
" BOOL_COL)"
"
\n
"
"VALUES("
"
\n
"
" 1,"
"
\n
"
" :BOOL_COL)"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
stmt
.
bindBool
(
":BOOL_COL"
,
insertValue
);
stmt
.
executeNonQuery
();
...
...
@@ -368,10 +385,10 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindBool_false) {
// Select the row back from the table
{
const
char
*
const
sql
=
"SELECT
"
"
BOOL_COL AS BOOL_COL "
"FROM
"
"
STMT_TEST"
;
"SELECT
"
"
\n
"
"
BOOL_COL AS BOOL_COL
"
"
\n
"
"FROM
"
"
\n
"
"
STMT_TEST"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
auto
rset
=
stmt
.
executeQuery
();
ASSERT_TRUE
(
rset
.
next
());
...
...
@@ -394,9 +411,11 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindString_invalid_bool_value) {
// Insert a row into the test table
{
const
char
*
const
sql
=
"INSERT INTO STMT_TEST("
"BOOL_COL) "
"VALUES("
"INSERT INTO STMT_TEST("
"
\n
"
" ID,"
"
\n
"
"BOOL_COL)"
"
\n
"
"VALUES("
"
\n
"
" 1,"
"
\n
"
":BOOL_COL)"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
stmt
.
bindString
(
":BOOL_COL"
,
insertValue
);
...
...
@@ -405,4 +424,62 @@ TEST_P(cta_rdbms_StmtTest, insert_with_bindString_invalid_bool_value) {
}
}
TEST_P
(
cta_rdbms_StmtTest
,
insert_same_primary_twice
)
{
using
namespace
cta
::
rdbms
;
const
uint64_t
insertValue
=
1234
;
// Insert an ID into the test table
{
const
char
*
const
sql
=
"INSERT INTO STMT_TEST("
"
\n
"
" ID)"
"
\n
"
"VALUES("
"
\n
"
" :ID)"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
stmt
.
bindUint64
(
":ID"
,
insertValue
);
stmt
.
executeNonQuery
();
}
// Select the ID back from the table
{
const
char
*
const
sql
=
"SELECT"
"
\n
"
" ID AS ID"
"
\n
"
"FROM"
"
\n
"
" STMT_TEST"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
auto
rset
=
stmt
.
executeQuery
();
ASSERT_TRUE
(
rset
.
next
());
const
auto
selectValue
=
rset
.
columnOptionalDouble
(
"ID"
);
ASSERT_TRUE
((
bool
)
selectValue
);
ASSERT_EQ
(
insertValue
,
selectValue
.
value
());
ASSERT_FALSE
(
rset
.
next
());
}
// Attempt to insert the same ID again
{
const
char
*
const
sql
=
"INSERT INTO STMT_TEST("
"
\n
"
" ID) "
"
\n
"
"VALUES("
"
\n
"
" :ID)"
;
auto
stmt
=
m_conn
.
createStmt
(
sql
);
stmt
.
bindUint64
(
":ID"
,
insertValue
);
switch
(
m_login
.
dbType
)
{
case
Login
::
DBTYPE_IN_MEMORY
:
case
Login
::
DBTYPE_ORACLE
:
case
Login
::
DBTYPE_POSTGRESQL
:
ASSERT_THROW
(
stmt
.
executeNonQuery
(),
cta
::
exception
::
DatabaseUniqueError
);
break
;
default:
ASSERT_THROW
(
stmt
.
executeNonQuery
(),
cta
::
exception
::
DatabasePrimaryKeyError
);
}
}
}
}
// namespace unitTests
rdbms/wrapper/OcciStmt.cpp
View file @
1015562f
...
...
@@ -17,6 +17,8 @@
*/
#include
"common/exception/DatabaseCheckConstraintError.hpp"
#include
"common/exception/DatabasePrimaryKeyError.hpp"
#include
"common/exception/DatabaseUniqueError.hpp"
#include
"common/exception/Exception.hpp"
#include
"common/exception/LostDatabaseConnection.hpp"
#include
"common/make_unique.hpp"
...
...
@@ -27,6 +29,7 @@
#include
"rdbms/wrapper/OcciStmt.hpp"
#include
<cstring>
#include
<iostream>
#include
<map>
#include
<sstream>
#include
<stdexcept>
...
...
@@ -268,9 +271,13 @@ void OcciStmt::executeNonQuery() {
}
throw
exception
::
LostDatabaseConnection
(
msg
.
str
());
}
if
(
2290
==
ex
.
getErrorCode
())
{
switch
(
ex
.
getErrorCode
())
{
case
1
:
throw
exception
::
DatabaseUniqueError
(
msg
.
str
());
case
2290
:
throw
exception
::
DatabaseCheckConstraintError
(
msg
.
str
());
}
else
{
default:
throw
exception
::
Exception
(
msg
.
str
());
}
}
...
...
rdbms/wrapper/Postgres.hpp
View file @
1015562f
...
...
@@ -19,11 +19,13 @@
#pragma once
#include
"common/exception/DatabaseCheckConstraintError.hpp"
#include
"common/exception/DatabaseUniqueError.hpp"
#include
"common/exception/Exception.hpp"
#include
"common/exception/LostDatabaseConnection.hpp"
#include
<algorithm>
#include
<cstring>
#include
<iostream>
#include
<libpq-fe.h>
#include
<string>
...
...
@@ -50,11 +52,13 @@ public:
pgstr
.
erase
(
std
::
remove
(
pgstr
.
begin
(),
pgstr
.
end
(),
'\n'
),
pgstr
.
end
());
}
std
::
string
resstr
;
bool
uniqueViolation
=
false
;
bool
checkViolation
=
false
;
if
(
nullptr
!=
res
)
{
resstr
=
"DB Result Status:"
+
std
::
to_string
(
PQresultStatus
(
res
));
const
char
*
const
e
=
PQresultErrorField
(
res
,
PG_DIAG_SQLSTATE
);
if
(
nullptr
!=
e
&&
'\0'
!=
*
e
)
{
uniqueViolation
=
0
==
std
::
strcmp
(
"23505"
,
e
);
checkViolation
=
0
==
std
::
strcmp
(
"23514"
,
e
);
resstr
+=
" SQLState:"
+
std
::
string
(
e
);
}
...
...
@@ -90,6 +94,9 @@ public:
if
(
badconn
)
{
throw
exception
::
LostDatabaseConnection
(
dbmsg
);
}
if
(
uniqueViolation
)
{
throw
exception
::
DatabaseUniqueError
(
dbmsg
);
}
if
(
checkViolation
)
{
throw
exception
::
DatabaseCheckConstraintError
(
dbmsg
);
}
...
...
rdbms/wrapper/SqliteStmt.cpp
View file @
1015562f
...
...
@@ -19,6 +19,7 @@
#include
"common/exception/DatabaseCheckConstraintError.hpp"
#include
"common/exception/DatabaseConstraintError.hpp"
#include
"common/exception/DatabasePrimaryKeyError.hpp"
#include
"common/exception/DatabaseUniqueError.hpp"
#include
"common/exception/Exception.hpp"
#include
"common/make_unique.hpp"
#include
"common/threading/MutexLocker.hpp"
...
...
@@ -286,12 +287,14 @@ void SqliteStmt::executeNonQuery() {
msg
<<
__FUNCTION__
<<
" failed for SQL statement "
<<
getSqlForException
()
+
": "
<<
Sqlite
::
rcToStr
(
stepRc
);
switch
(
stepRc
)
{
case
SQLITE_CONSTRAINT_PRIMARYKEY
:
throw
exception
::
DatabasePrimaryKeyError
(
msg
.
str
());
case
SQLITE_CONSTRAINT_CHECK
:
throw
exception
::
DatabaseCheckConstraintError
(
msg
.
str
());
case
SQLITE_CONSTRAINT
:
throw
exception
::
DatabaseConstraintError
(
msg
.
str
());
case
SQLITE_CONSTRAINT_CHECK
:
throw
exception
::
DatabaseCheckConstraintError
(
msg
.
str
());
case
SQLITE_CONSTRAINT_PRIMARYKEY
:
throw
exception
::
DatabasePrimaryKeyError
(
msg
.
str
());
case
SQLITE_CONSTRAINT_UNIQUE
:
throw
exception
::
DatabaseUniqueError
(
msg
.
str
());
default:
if
((
stepRc
&
0xFF
)
==
SQLITE_CONSTRAINT
)
throw
exception
::
DatabaseConstraintError
(
msg
.
str
());
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment