RdbmsCatalogue.cpp 210 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * 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/>.
 */

19
#include "catalogue/ArchiveFileRow.hpp"
20
#include "catalogue/RdbmsArchiveFileItorImpl.hpp"
21
#include "catalogue/RdbmsCatalogue.hpp"
22
#include "catalogue/retryOnLostConnection.hpp"
23
#include "catalogue/SqliteCatalogueSchema.hpp"
24
25
#include "catalogue/UserSpecifiedANonEmptyTape.hpp"
#include "catalogue/UserSpecifiedANonExistentTape.hpp"
26
#include "catalogue/UserSpecifiedAnEmptyStringComment.hpp"
27
#include "catalogue/UserSpecifiedAnEmptyStringDiskInstanceName.hpp"
28
#include "catalogue/UserSpecifiedAnEmptyStringLogicalLibraryName.hpp"
29
#include "catalogue/UserSpecifiedAnEmptyStringStorageClassName.hpp"
30
#include "catalogue/UserSpecifiedAnEmptyStringTapePoolName.hpp"
31
#include "catalogue/UserSpecifiedAnEmptyStringUsername.hpp"
32
#include "catalogue/UserSpecifiedAnEmptyStringVid.hpp"
33
#include "catalogue/UserSpecifiedAnEmptyStringVo.hpp"
34
#include "catalogue/UserSpecifiedAZeroCapacity.hpp"
35
#include "catalogue/UserSpecifiedAZeroCopyNb.hpp"
36
#include "common/dataStructures/TapeFile.hpp"
37
#include "common/exception/Exception.hpp"
38
#include "common/exception/UserError.hpp"
39
#include "common/make_unique.hpp"
40
#include "common/threading/MutexLocker.hpp"
41
#include "common/Timer.hpp"
42
#include "common/utils/utils.hpp"
43
#include "rdbms/AutoRollback.hpp"
44

45
#include <ctype.h>
46
47
#include <memory>
#include <time.h>
48
#include <common/exception/LostDatabaseConnection.hpp>
49

50
51
52
namespace cta {
namespace catalogue {

53
54
55
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
56
RdbmsCatalogue::RdbmsCatalogue(
57
  log::Logger &log,
58
  const rdbms::Login &login,
59
  const uint64_t nbConns,
60
61
  const uint64_t nbArchiveFileListingConns,
  const uint32_t maxTriesToConnect):
62
  m_log(log),
63
  m_connPool(login, nbConns),
64
  m_archiveFileListingConnPool(login, nbArchiveFileListingConns),
Steven Murray's avatar
Steven Murray committed
65
66
67
68
  m_maxTriesToConnect(maxTriesToConnect),
  m_tapeCopyToPoolCache(10),
  m_groupMountPolicyCache(10),
  m_userMountPolicyCache(10),
69
70
  m_expectedNbArchiveRoutesCache(10),
  m_isAdminCache(10) {
71
72
73
74
75
}

//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
76
RdbmsCatalogue::~RdbmsCatalogue() {
77
78
79
80
81
}

//------------------------------------------------------------------------------
// createAdminUser
//------------------------------------------------------------------------------
82
void RdbmsCatalogue::createAdminUser(
Steven Murray's avatar
Steven Murray committed
83
  const common::dataStructures::SecurityIdentity &admin,
84
  const std::string &username,
85
  const std::string &comment) {
Steven Murray's avatar
Steven Murray committed
86
  try {
87
88
89
90
91
    if(username.empty()) {
      throw UserSpecifiedAnEmptyStringUsername("Cannot create admin user because the username is an empty string");
    }

    if(comment.empty()) {
92
      throw UserSpecifiedAnEmptyStringComment("Cannot create admin user because the comment is an empty string");
93
94
    }

95
    auto conn = m_connPool.getConn();
96
    if (adminUserExists(conn, username)) {
97
      throw exception::UserError(std::string("Cannot create admin user " + username +
98
99
        " because an admin user with the same name already exists"));
    }
100
    const uint64_t now = time(nullptr);
Steven Murray's avatar
Steven Murray committed
101
102
103
104
105
106
107
108
109
110
111
112
113
    const char *const sql =
      "INSERT INTO ADMIN_USER("
        "ADMIN_USER_NAME,"

        "USER_COMMENT,"

        "CREATION_LOG_USER_NAME,"
        "CREATION_LOG_HOST_NAME,"
        "CREATION_LOG_TIME,"

        "LAST_UPDATE_USER_NAME,"
        "LAST_UPDATE_HOST_NAME,"
        "LAST_UPDATE_TIME)"
114
      "VALUES("
Steven Murray's avatar
Steven Murray committed
115
116
117
118
119
120
121
122
        ":ADMIN_USER_NAME,"

        ":USER_COMMENT,"

        ":CREATION_LOG_USER_NAME,"
        ":CREATION_LOG_HOST_NAME,"
        ":CREATION_LOG_TIME,"

123
124
125
        ":LAST_UPDATE_USER_NAME,"
        ":LAST_UPDATE_HOST_NAME,"
        ":LAST_UPDATE_TIME)";
126
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
Steven Murray's avatar
Steven Murray committed
127

128
    stmt.bindString(":ADMIN_USER_NAME", username);
Steven Murray's avatar
Steven Murray committed
129

130
    stmt.bindString(":USER_COMMENT", comment);
Steven Murray's avatar
Steven Murray committed
131

132
133
134
    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
    stmt.bindUint64(":CREATION_LOG_TIME", now);
Steven Murray's avatar
Steven Murray committed
135

136
137
138
    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
    stmt.bindUint64(":LAST_UPDATE_TIME", now);
139

140
    stmt.executeNonQuery();
141
142
143
144
  } catch(exception::UserError &) {
    throw;
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
145
146
147
148
149
150
151
    throw;
  }
}

//------------------------------------------------------------------------------
// adminUserExists
//------------------------------------------------------------------------------
152
bool RdbmsCatalogue::adminUserExists(rdbms::Conn &conn, const std::string adminUsername) const {
153
154
155
156
157
158
159
  try {
    const char *const sql =
      "SELECT "
        "ADMIN_USER_NAME AS ADMIN_USER_NAME "
      "FROM "
        "ADMIN_USER "
      "WHERE "
160
        "ADMIN_USER_NAME = :ADMIN_USER_NAME";
161
162
163
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    stmt.bindString(":ADMIN_USER_NAME", adminUsername);
    auto rset = stmt.executeQuery();
164
    return rset.next();
165
166
  } catch(exception::UserError &) {
    throw;
167
168
169
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
Steven Murray's avatar
Steven Murray committed
170
  }
171
172
173
174
175
}

//------------------------------------------------------------------------------
// deleteAdminUser
//------------------------------------------------------------------------------
176
void RdbmsCatalogue::deleteAdminUser(const std::string &username) {
177
  try {
178
    const char *const sql = "DELETE FROM ADMIN_USER WHERE ADMIN_USER_NAME = :ADMIN_USER_NAME";
179
    auto conn = m_connPool.getConn();
180
181
182
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
    stmt.bindString(":ADMIN_USER_NAME", username);
    stmt.executeNonQuery();
183

184
    if(0 == stmt.getNbAffectedRows()) {
185
      throw exception::UserError(std::string("Cannot delete admin-user ") + username + " because they do not exist");
186
    }
187
188
189
190
  } catch(exception::UserError &) {
    throw;
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
191
192
    throw;
  }
Steven Murray's avatar
Steven Murray committed
193
}
194
195
196
197

//------------------------------------------------------------------------------
// getAdminUsers
//------------------------------------------------------------------------------
198
std::list<common::dataStructures::AdminUser> RdbmsCatalogue::getAdminUsers() const {
Steven Murray's avatar
Steven Murray committed
199
200
201
202
203
  try {
    std::list<common::dataStructures::AdminUser> admins;
    const char *const sql =
      "SELECT "
        "ADMIN_USER_NAME AS ADMIN_USER_NAME,"
204

Steven Murray's avatar
Steven Murray committed
205
        "USER_COMMENT AS USER_COMMENT,"
206

207
208
209
        "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME,"
        "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME,"
        "CREATION_LOG_TIME AS CREATION_LOG_TIME,"
210

211
212
213
        "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME,"
        "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME,"
        "LAST_UPDATE_TIME AS LAST_UPDATE_TIME "
214
      "FROM "
215
216
217
        "ADMIN_USER "
      "ORDER BY "
        "ADMIN_USER_NAME";
218
    auto conn = m_connPool.getConn();
219
220
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    auto rset = stmt.executeQuery();
221
    while (rset.next()) {
Steven Murray's avatar
Steven Murray committed
222
      common::dataStructures::AdminUser admin;
223

224
225
226
227
228
229
230
231
      admin.name = rset.columnString("ADMIN_USER_NAME");
      admin.comment = rset.columnString("USER_COMMENT");
      admin.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME");
      admin.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME");
      admin.creationLog.time = rset.columnUint64("CREATION_LOG_TIME");
      admin.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME");
      admin.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME");
      admin.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME");
232

Steven Murray's avatar
Steven Murray committed
233
234
      admins.push_back(admin);
    }
235

Steven Murray's avatar
Steven Murray committed
236
    return admins;
237
238
  } catch(exception::UserError &) {
    throw;
239
240
241
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
Steven Murray's avatar
Steven Murray committed
242
  }
243
244
245
246
247
}

//------------------------------------------------------------------------------
// modifyAdminUserComment
//------------------------------------------------------------------------------
Steven Murray's avatar
Steven Murray committed
248
void RdbmsCatalogue::modifyAdminUserComment(const common::dataStructures::SecurityIdentity &admin,
249
250
  const std::string &username, const std::string &comment) {
  try {
251
252
253
254
255
    if(username.empty()) {
      throw UserSpecifiedAnEmptyStringUsername("Cannot modify admin user because the username is an empty string");
    }

    if(comment.empty()) {
256
      throw UserSpecifiedAnEmptyStringComment("Cannot modify admin user because the comment is an empty string");
257
258
    }

259
260
261
262
263
264
265
    const time_t now = time(nullptr);
    const char *const sql =
      "UPDATE ADMIN_USER SET "
        "USER_COMMENT = :USER_COMMENT,"
        "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME,"
        "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME,"
        "LAST_UPDATE_TIME = :LAST_UPDATE_TIME "
266
      "WHERE "
267
268
        "ADMIN_USER_NAME = :ADMIN_USER_NAME";
    auto conn = m_connPool.getConn();
269
270
271
272
273
274
275
276
277
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
    stmt.bindString(":USER_COMMENT", comment);
    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
    stmt.bindUint64(":LAST_UPDATE_TIME", now);
    stmt.bindString(":ADMIN_USER_NAME", username);
    stmt.executeNonQuery();

    if(0 == stmt.getNbAffectedRows()) {
278
279
280
281
      throw exception::UserError(std::string("Cannot modify admin user ") + username + " because they do not exist");
    }
  } catch(exception::UserError &) {
    throw;
282
283
284
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
285
  }
Steven Murray's avatar
Steven Murray committed
286
}
287
288
289
290

//------------------------------------------------------------------------------
// createStorageClass
//------------------------------------------------------------------------------
291
void RdbmsCatalogue::createStorageClass(
Steven Murray's avatar
Steven Murray committed
292
  const common::dataStructures::SecurityIdentity &admin,
293
  const common::dataStructures::StorageClass &storageClass) {
Steven Murray's avatar
Steven Murray committed
294
  try {
295
    if(storageClass.diskInstance.empty()) {
296
297
      throw UserSpecifiedAnEmptyStringDiskInstanceName("Cannot create storage class because the disk instance name is"
        " an empty string");
298
299
300
    }

    if(storageClass.name.empty()) {
301
302
      throw UserSpecifiedAnEmptyStringStorageClassName("Cannot create storage class because the storage class name is"
        " an empty string");
303
304
305
    }

    if(storageClass.comment.empty()) {
306
      throw UserSpecifiedAnEmptyStringComment("Cannot create storage class because the comment is an empty string");
307
308
    }

309
    auto conn = m_connPool.getConn();
310
    if(storageClassExists(conn, storageClass.diskInstance, storageClass.name)) {
311
312
      throw exception::UserError(std::string("Cannot create storage class ") + storageClass.diskInstance + ":" +
        storageClass.name + " because it already exists");
313
    }
314
    const uint64_t storageClassId = getNextStorageClassId(conn);
315
    const time_t now = time(nullptr);
Steven Murray's avatar
Steven Murray committed
316
317
    const char *const sql =
      "INSERT INTO STORAGE_CLASS("
318
        "STORAGE_CLASS_ID,"
319
        "DISK_INSTANCE_NAME,"
Steven Murray's avatar
Steven Murray committed
320
321
322
323
324
325
326
327
328
329
330
331
        "STORAGE_CLASS_NAME,"
        "NB_COPIES,"

        "USER_COMMENT,"

        "CREATION_LOG_USER_NAME,"
        "CREATION_LOG_HOST_NAME,"
        "CREATION_LOG_TIME,"

        "LAST_UPDATE_USER_NAME,"
        "LAST_UPDATE_HOST_NAME,"
        "LAST_UPDATE_TIME)"
332
      "VALUES("
333
        ":STORAGE_CLASS_ID,"
334
        ":DISK_INSTANCE_NAME,"
Steven Murray's avatar
Steven Murray committed
335
336
337
338
339
340
341
342
343
        ":STORAGE_CLASS_NAME,"
        ":NB_COPIES,"

        ":USER_COMMENT,"

        ":CREATION_LOG_USER_NAME,"
        ":CREATION_LOG_HOST_NAME,"
        ":CREATION_LOG_TIME,"

344
345
346
        ":LAST_UPDATE_USER_NAME,"
        ":LAST_UPDATE_HOST_NAME,"
        ":LAST_UPDATE_TIME)";
347
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
Steven Murray's avatar
Steven Murray committed
348

349
    stmt.bindUint64(":STORAGE_CLASS_ID", storageClassId);
350
351
352
    stmt.bindString(":DISK_INSTANCE_NAME", storageClass.diskInstance);
    stmt.bindString(":STORAGE_CLASS_NAME", storageClass.name);
    stmt.bindUint64(":NB_COPIES", storageClass.nbCopies);
Steven Murray's avatar
Steven Murray committed
353

354
    stmt.bindString(":USER_COMMENT", storageClass.comment);
Steven Murray's avatar
Steven Murray committed
355

356
357
358
    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
    stmt.bindUint64(":CREATION_LOG_TIME", now);
Steven Murray's avatar
Steven Murray committed
359

360
361
362
    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
    stmt.bindUint64(":LAST_UPDATE_TIME", now);
363

364
    stmt.executeNonQuery();
365
  } catch(exception::UserError &) {
366
    throw;
367
368
369
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
370
371
372
373
374
375
  }
}

//------------------------------------------------------------------------------
// storageClassExists
//------------------------------------------------------------------------------
376
bool RdbmsCatalogue::storageClassExists(rdbms::Conn &conn, const std::string &diskInstanceName,
377
  const std::string &storageClassName) const {
378
379
380
  try {
    const char *const sql =
      "SELECT "
381
        "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, "
382
383
384
385
        "STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME "
      "FROM "
        "STORAGE_CLASS "
      "WHERE "
386
        "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
387
        "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME";
388
389
390
391
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
    auto rset = stmt.executeQuery();
392
    return rset.next();
393
394
  } catch(exception::UserError &) {
    throw;
395
396
397
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
Steven Murray's avatar
Steven Murray committed
398
  }
399
400
401
402
403
}

//------------------------------------------------------------------------------
// deleteStorageClass
//------------------------------------------------------------------------------
404
void RdbmsCatalogue::deleteStorageClass(const std::string &diskInstanceName, const std::string &storageClassName) {
405
406
407
408
409
  try {
    const char *const sql =
      "DELETE FROM "
        "STORAGE_CLASS "
      "WHERE "
410
        "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
411
        "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME";
412
    auto conn = m_connPool.getConn();
413
    auto stmt = conn.createStmt(sql,rdbms::AutocommitMode::ON);
414

415
416
    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
417

418
419
    stmt.executeNonQuery();
    if(0 == stmt.getNbAffectedRows()) {
420
421
      throw exception::UserError(std::string("Cannot delete storage-class ") + diskInstanceName + ":" +
        storageClassName + " because it does not exist");
422
    }
423
  } catch(exception::UserError &) {
424
    throw;
425
426
427
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
428
  }
Steven Murray's avatar
Steven Murray committed
429
}
430
431
432
433

//------------------------------------------------------------------------------
// getStorageClasses
//------------------------------------------------------------------------------
434
std::list<common::dataStructures::StorageClass> RdbmsCatalogue::getStorageClasses() const {
Steven Murray's avatar
Steven Murray committed
435
436
437
438
  try {
    std::list<common::dataStructures::StorageClass> storageClasses;
    const char *const sql =
      "SELECT "
439
        "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME,"
Steven Murray's avatar
Steven Murray committed
440
        "STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME,"
441
        "NB_COPIES AS NB_COPIES,"
Steven Murray's avatar
Steven Murray committed
442
443
444

        "USER_COMMENT AS USER_COMMENT,"

445
446
447
        "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME,"
        "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME,"
        "CREATION_LOG_TIME AS CREATION_LOG_TIME,"
Steven Murray's avatar
Steven Murray committed
448

449
450
451
        "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME,"
        "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME,"
        "LAST_UPDATE_TIME AS LAST_UPDATE_TIME "
452
      "FROM "
453
454
455
        "STORAGE_CLASS "
      "ORDER BY "
        "DISK_INSTANCE_NAME, STORAGE_CLASS_NAME";
456
    auto conn = m_connPool.getConn();
457
458
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    auto rset = stmt.executeQuery();
459
    while (rset.next()) {
Steven Murray's avatar
Steven Murray committed
460
461
      common::dataStructures::StorageClass storageClass;

462
463
464
465
466
467
468
469
470
471
      storageClass.diskInstance = rset.columnString("DISK_INSTANCE_NAME");
      storageClass.name = rset.columnString("STORAGE_CLASS_NAME");
      storageClass.nbCopies = rset.columnUint64("NB_COPIES");
      storageClass.comment = rset.columnString("USER_COMMENT");
      storageClass.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME");
      storageClass.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME");
      storageClass.creationLog.time = rset.columnUint64("CREATION_LOG_TIME");
      storageClass.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME");
      storageClass.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME");
      storageClass.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME");
Steven Murray's avatar
Steven Murray committed
472
473

      storageClasses.push_back(storageClass);
474
475
    }

Steven Murray's avatar
Steven Murray committed
476
    return storageClasses;
477
478
  } catch(exception::UserError &) {
    throw;
479
480
481
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
482
483
484
485
486
487
  }
}

//------------------------------------------------------------------------------
// modifyStorageClassNbCopies
//------------------------------------------------------------------------------
Steven Murray's avatar
Steven Murray committed
488
void RdbmsCatalogue::modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin,
489
490
491
492
493
494
495
496
497
  const std::string &instanceName, const std::string &name, const uint64_t nbCopies) {
  try {
    const time_t now = time(nullptr);
    const char *const sql =
      "UPDATE STORAGE_CLASS SET "
        "NB_COPIES = :NB_COPIES,"
        "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME,"
        "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME,"
        "LAST_UPDATE_TIME = :LAST_UPDATE_TIME "
498
      "WHERE "
499
500
501
        "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
        "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME";
    auto conn = m_connPool.getConn();
502
503
504
505
506
507
508
509
510
511
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
    stmt.bindUint64(":NB_COPIES", nbCopies);
    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
    stmt.bindUint64(":LAST_UPDATE_TIME", now);
    stmt.bindString(":DISK_INSTANCE_NAME", instanceName);
    stmt.bindString(":STORAGE_CLASS_NAME", name);
    stmt.executeNonQuery();

    if(0 == stmt.getNbAffectedRows()) {
512
513
514
515
516
      throw exception::UserError(std::string("Cannot modify storage class ") + instanceName + ":" + name +
        " because it does not exist");
    }
  } catch(exception::UserError &) {
    throw;
517
518
519
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
520
  }
Steven Murray's avatar
Steven Murray committed
521
}
522
523
524
525

//------------------------------------------------------------------------------
// modifyStorageClassComment
//------------------------------------------------------------------------------
Steven Murray's avatar
Steven Murray committed
526
void RdbmsCatalogue::modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin,
527
528
529
530
531
532
533
534
535
  const std::string &instanceName, const std::string &name, const std::string &comment) {
  try {
    const time_t now = time(nullptr);
    const char *const sql =
      "UPDATE STORAGE_CLASS SET "
        "USER_COMMENT = :USER_COMMENT,"
        "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME,"
        "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME,"
        "LAST_UPDATE_TIME = :LAST_UPDATE_TIME "
536
      "WHERE "
537
538
539
        "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
        "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME";
    auto conn = m_connPool.getConn();
540
541
542
543
544
545
546
547
548
549
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
    stmt.bindString(":USER_COMMENT", comment);
    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
    stmt.bindUint64(":LAST_UPDATE_TIME", now);
    stmt.bindString(":DISK_INSTANCE_NAME", instanceName);
    stmt.bindString(":STORAGE_CLASS_NAME", name);
    stmt.executeNonQuery();

    if(0 == stmt.getNbAffectedRows()) {
550
551
552
553
554
      throw exception::UserError(std::string("Cannot modify storage class ") + instanceName + ":" + name +
        " because it does not exist");
    }
  } catch(exception::UserError &) {
    throw;
555
556
557
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
558
  }
Steven Murray's avatar
Steven Murray committed
559
}
560
561
562
563

//------------------------------------------------------------------------------
// createTapePool
//------------------------------------------------------------------------------
564
void RdbmsCatalogue::createTapePool(
Steven Murray's avatar
Steven Murray committed
565
  const common::dataStructures::SecurityIdentity &admin,
566
  const std::string &name,
567
  const std::string &vo,
568
569
570
  const uint64_t nbPartialTapes,
  const bool encryptionValue,
  const std::string &comment) {
Steven Murray's avatar
Steven Murray committed
571
  try {
572
573
574
575
576
    if(name.empty()) {
      throw UserSpecifiedAnEmptyStringTapePoolName("Cannot create tape pool because the tape pool name is an empty string");
    }

    if(vo.empty()) {
577
      throw UserSpecifiedAnEmptyStringVo("Cannot create tape pool because the VO is an empty string");
578
579
580
    }

    if(comment.empty()) {
581
      throw UserSpecifiedAnEmptyStringComment("Cannot create tape pool because the comment is an empty string");
582
583
    }

584
    auto conn = m_connPool.getConn();
585

586
    if(tapePoolExists(conn, name)) {
587
      throw exception::UserError(std::string("Cannot create tape pool ") + name +
588
589
        " because a tape pool with the same name already exists");
    }
590
    const time_t now = time(nullptr);
Steven Murray's avatar
Steven Murray committed
591
592
593
    const char *const sql =
      "INSERT INTO TAPE_POOL("
        "TAPE_POOL_NAME,"
594
        "VO,"
Steven Murray's avatar
Steven Murray committed
595
596
597
598
599
600
601
602
603
604
605
606
        "NB_PARTIAL_TAPES,"
        "IS_ENCRYPTED,"

        "USER_COMMENT,"

        "CREATION_LOG_USER_NAME,"
        "CREATION_LOG_HOST_NAME,"
        "CREATION_LOG_TIME,"

        "LAST_UPDATE_USER_NAME,"
        "LAST_UPDATE_HOST_NAME,"
        "LAST_UPDATE_TIME)"
607
      "VALUES("
Steven Murray's avatar
Steven Murray committed
608
        ":TAPE_POOL_NAME,"
609
        ":VO,"
Steven Murray's avatar
Steven Murray committed
610
611
612
613
614
615
616
617
618
        ":NB_PARTIAL_TAPES,"
        ":IS_ENCRYPTED,"

        ":USER_COMMENT,"

        ":CREATION_LOG_USER_NAME,"
        ":CREATION_LOG_HOST_NAME,"
        ":CREATION_LOG_TIME,"

619
620
621
        ":LAST_UPDATE_USER_NAME,"
        ":LAST_UPDATE_HOST_NAME,"
        ":LAST_UPDATE_TIME)";
622
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
Steven Murray's avatar
Steven Murray committed
623

624
    stmt.bindString(":TAPE_POOL_NAME", name);
625
    stmt.bindString(":VO", vo);
626
627
    stmt.bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes);
    stmt.bindBool(":IS_ENCRYPTED", encryptionValue);
Steven Murray's avatar
Steven Murray committed
628

629
    stmt.bindString(":USER_COMMENT", comment);
Steven Murray's avatar
Steven Murray committed
630

631
632
633
    stmt.bindString(":CREATION_LOG_USER_NAME", admin.username);
    stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host);
    stmt.bindUint64(":CREATION_LOG_TIME", now);
Steven Murray's avatar
Steven Murray committed
634

635
636
637
    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
    stmt.bindUint64(":LAST_UPDATE_TIME", now);
638

639
    stmt.executeNonQuery();
640
  } catch(exception::UserError &) {
641
    throw;
642
643
644
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
645
646
647
648
649
650
651
652
653
654
  }
}

//------------------------------------------------------------------------------
// tapePoolExists
//------------------------------------------------------------------------------
bool RdbmsCatalogue::tapePoolExists(const std::string &tapePoolName) const {
  try {
    auto conn = m_connPool.getConn();
    return tapePoolExists(conn, tapePoolName);
655
656
  } catch(exception::UserError &) {
    throw;
657
658
659
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
Steven Murray's avatar
Steven Murray committed
660
  }
661
662
}

663
664
665
//------------------------------------------------------------------------------
// tapePoolExists
//------------------------------------------------------------------------------
666
bool RdbmsCatalogue::tapePoolExists(rdbms::Conn &conn, const std::string &tapePoolName) const {
667
668
669
670
671
672
673
  try {
    const char *const sql =
      "SELECT "
        "TAPE_POOL_NAME AS TAPE_POOL_NAME "
      "FROM "
        "TAPE_POOL "
      "WHERE "
674
        "TAPE_POOL_NAME = :TAPE_POOL_NAME";
675
676
677
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    stmt.bindString(":TAPE_POOL_NAME", tapePoolName);
    auto rset = stmt.executeQuery();
678
    return rset.next();
679
680
  } catch(exception::UserError &) {
    throw;
681
682
683
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
684
685
686
  }
}

687
688
689
//------------------------------------------------------------------------------
// archiveFileExists
//------------------------------------------------------------------------------
690
bool RdbmsCatalogue::archiveFileIdExists(rdbms::Conn &conn, const uint64_t archiveFileId) const {
691
692
693
694
695
696
697
698
  try {
    const char *const sql =
      "SELECT "
        "ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID "
      "FROM "
        "ARCHIVE_FILE "
      "WHERE "
        "ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID";
699
700
701
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId);
    auto rset = stmt.executeQuery();
702
    return rset.next();
703
704
  } catch(exception::UserError &) {
    throw;
705
706
707
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
708
709
710
  }
}

711
712
713
//------------------------------------------------------------------------------
// diskFileIdExists
//------------------------------------------------------------------------------
714
bool RdbmsCatalogue::diskFileIdExists(rdbms::Conn &conn, const std::string &diskInstanceName,
715
716
717
718
719
720
721
722
723
724
725
  const std::string &diskFileId) const {
  try {
    const char *const sql =
      "SELECT "
        "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, "
        "DISK_FILE_ID AS DISK_FILE_ID "
      "FROM "
        "ARCHIVE_FILE "
      "WHERE "
        "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
        "DISK_FILE_ID = :DISK_FILE_ID";
726
727
728
729
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
    stmt.bindString(":DISK_FILE_ID", diskFileId);
    auto rset = stmt.executeQuery();
730
    return rset.next();
731
732
  } catch(exception::UserError &) {
    throw;
733
734
735
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
736
737
738
  }
}

739
740
741
//------------------------------------------------------------------------------
// diskFilePathExists
//------------------------------------------------------------------------------
742
bool RdbmsCatalogue::diskFilePathExists(rdbms::Conn &conn, const std::string &diskInstanceName,
743
744
745
746
747
748
749
750
751
752
753
  const std::string &diskFilePath) const {
  try {
    const char *const sql =
      "SELECT "
        "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, "
        "DISK_FILE_PATH AS DISK_FILE_PATH "
      "FROM "
        "ARCHIVE_FILE "
      "WHERE "
        "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
        "DISK_FILE_PATH = :DISK_FILE_PATH";
754
755
756
757
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
    stmt.bindString(":DISK_FILE_PATH", diskFilePath);
    auto rset = stmt.executeQuery();
758
    return rset.next();
759
760
  } catch(exception::UserError &) {
    throw;
761
762
763
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
764
765
766
  }
}

767
768
769
//------------------------------------------------------------------------------
// diskFileUserExists
//------------------------------------------------------------------------------
770
bool RdbmsCatalogue::diskFileUserExists(rdbms::Conn &conn, const std::string &diskInstanceName,
771
772
773
774
775
776
777
778
779
780
781
  const std::string &diskFileUser) const {
  try {
    const char *const sql =
      "SELECT "
        "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, "
        "DISK_FILE_USER AS DISK_FILE_USER "
      "FROM "
        "ARCHIVE_FILE "
      "WHERE "
        "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
        "DISK_FILE_USER = :DISK_FILE_USER";
782
783
784
785
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
    stmt.bindString(":DISK_FILE_USER", diskFileUser);
    auto rset = stmt.executeQuery();
786
    return rset.next();
787
788
  } catch(exception::UserError &) {
    throw;
789
790
791
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
792
793
794
  }
}

795
796
797
//------------------------------------------------------------------------------
// diskFileGroupExists
//------------------------------------------------------------------------------
798
bool RdbmsCatalogue::diskFileGroupExists(rdbms::Conn &conn, const std::string &diskInstanceName,
799
800
801
802
803
804
805
806
807
808
809
  const std::string &diskFileGroup) const {
  try {
    const char *const sql =
      "SELECT "
        "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, "
        "DISK_FILE_GROUP AS DISK_FILE_GROUP "
      "FROM "
        "ARCHIVE_FILE "
      "WHERE "
        "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
        "DISK_FILE_GROUP = :DISK_FILE_GROUP";
810
811
812
813
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
    stmt.bindString(":DISK_FILE_GROUP", diskFileGroup);
    auto rset = stmt.executeQuery();
814
    return rset.next();
815
816
  } catch(exception::UserError &) {
    throw;
817
818
819
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
820
821
822
  }
}

823
824
825
//------------------------------------------------------------------------------
// archiveRouteExists
//------------------------------------------------------------------------------
826
bool RdbmsCatalogue::archiveRouteExists(rdbms::Conn &conn, const std::string &diskInstanceName,
827
828
829
830
  const std::string &storageClassName, const uint64_t copyNb) const {
  try {
    const char *const sql =
      "SELECT "
831
832
        "ARCHIVE_ROUTE.STORAGE_CLASS_ID AS STORAGE_CLASS_ID,"
        "ARCHIVE_ROUTE.COPY_NB AS COPY_NB "
833
834
      "FROM "
        "ARCHIVE_ROUTE "
835
836
      "INNER JOIN STORAGE_CLASS ON "
        "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID "
837
      "WHERE "
838
839
840
        "STORAGE_CLASS.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND "
        "STORAGE_CLASS.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME AND "
        "ARCHIVE_ROUTE.COPY_NB = :COPY_NB";
841
842
843
844
845
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
    stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
    stmt.bindUint64(":COPY_NB", copyNb);
    auto rset = stmt.executeQuery();
846
    return rset.next();
847
848
  } catch(exception::UserError &) {
    throw;
849
850
851
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
852
853
854
  }
}

855
856
857
//------------------------------------------------------------------------------
// deleteTapePool
//------------------------------------------------------------------------------
858
void RdbmsCatalogue::deleteTapePool(const std::string &name) {
859
  try {
860
    const char *const sql = "DELETE FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME";
861
    auto conn = m_connPool.getConn();
862
863
864
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
    stmt.bindString(":TAPE_POOL_NAME", name);
    stmt.executeNonQuery();
865

866
    if(0 == stmt.getNbAffectedRows()) {
867
      throw exception::UserError(std::string("Cannot delete tape-pool ") + name + " because it does not exist");
868
    }
869
  } catch(exception::UserError &) {
870
    throw;
871
872
873
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
874
  }
Steven Murray's avatar
Steven Murray committed
875
}
876
877
878
879

//------------------------------------------------------------------------------
// getTapePools
//------------------------------------------------------------------------------
880
std::list<TapePool> RdbmsCatalogue::getTapePools() const {
Steven Murray's avatar
Steven Murray committed
881
  try {
882
    std::list<TapePool> pools;
Steven Murray's avatar
Steven Murray committed
883
884
    const char *const sql =
      "SELECT "
885
        "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME,"
886
        "COALESCE(TAPE_POOL.VO, 'NONE') AS VO," // TBD Remove COALESCE
887
888
        "TAPE_POOL.NB_PARTIAL_TAPES AS NB_PARTIAL_TAPES,"
        "TAPE_POOL.IS_ENCRYPTED AS IS_ENCRYPTED,"
Steven Murray's avatar
Steven Murray committed
889

890
        "COALESCE(COUNT(TAPE.VID), 0) AS NB_TAPES,"
891
892
893
        "COALESCE(SUM(TAPE.CAPACITY_IN_BYTES), 0) AS CAPACITY_IN_BYTES,"
        "COALESCE(SUM(TAPE.DATA_IN_BYTES), 0) AS DATA_IN_BYTES,"
        "COALESCE(SUM(TAPE.LAST_FSEQ), 0) AS NB_PHYSICAL_FILES,"
Steven Murray's avatar
Steven Murray committed
894

895
        "TAPE_POOL.USER_COMMENT AS USER_COMMENT,"
Steven Murray's avatar
Steven Murray committed
896

897
898
899
900
901
902
903
        "TAPE_POOL.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME,"
        "TAPE_POOL.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME,"
        "TAPE_POOL.CREATION_LOG_TIME AS CREATION_LOG_TIME,"

        "TAPE_POOL.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME,"
        "TAPE_POOL.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME,"
        "TAPE_POOL.LAST_UPDATE_TIME AS LAST_UPDATE_TIME "
904
      "FROM "
905
        "TAPE_POOL "
906
907
908
909
      "LEFT OUTER JOIN TAPE ON "
        "TAPE_POOL.TAPE_POOL_NAME = TAPE.TAPE_POOL_NAME "
      "GROUP BY "
        "TAPE_POOL.TAPE_POOL_NAME,"
910
        "TAPE_POOL.VO,"
911
912
913
914
915
916
917
918
919
        "TAPE_POOL.NB_PARTIAL_TAPES,"
        "TAPE_POOL.IS_ENCRYPTED,"
        "TAPE_POOL.USER_COMMENT,"
        "TAPE_POOL.CREATION_LOG_USER_NAME,"
        "TAPE_POOL.CREATION_LOG_HOST_NAME,"
        "TAPE_POOL.CREATION_LOG_TIME,"
        "TAPE_POOL.LAST_UPDATE_USER_NAME,"
        "TAPE_POOL.LAST_UPDATE_HOST_NAME,"
        "TAPE_POOL.LAST_UPDATE_TIME "
920
921
      "ORDER BY "
        "TAPE_POOL_NAME";
922

923
    auto conn = m_connPool.getConn();
924
925
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::OFF);
    auto rset = stmt.executeQuery();
926
    while (rset.next()) {
927
      TapePool pool;
Steven Murray's avatar
Steven Murray committed
928

929
      pool.name = rset.columnString("TAPE_POOL_NAME");
930
      pool.vo = rset.columnString("VO");
931
932
      pool.nbPartialTapes = rset.columnUint64("NB_PARTIAL_TAPES");
      pool.encryption = rset.columnBool("IS_ENCRYPTED");
933
      pool.nbTapes = rset.columnUint64("NB_TAPES");
934
935
      pool.capacityBytes = rset.columnUint64("CAPACITY_IN_BYTES");
      pool.dataBytes = rset.columnUint64("DATA_IN_BYTES");
936
      pool.nbPhysicalFiles = rset.columnUint64("NB_PHYSICAL_FILES");
937
938
939
940
941
942
943
      pool.comment = rset.columnString("USER_COMMENT");
      pool.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME");
      pool.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME");
      pool.creationLog.time = rset.columnUint64("CREATION_LOG_TIME");
      pool.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME");
      pool.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME");
      pool.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME");
Steven Murray's avatar
Steven Murray committed
944
945

      pools.push_back(pool);
946
947
    }

Steven Murray's avatar
Steven Murray committed
948
    return pools;
949
950
  } catch(exception::UserError &) {
    throw;
951
952
953
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
954
955
956
  }
}

957
958
959
960
961
962
//------------------------------------------------------------------------------
// modifyTapePoolVO
//------------------------------------------------------------------------------
void RdbmsCatalogue::modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin,
  const std::string &name, const std::string &vo) {
  try {
963
964
965
966
967
    if(name.empty()) {
      throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty"
        " string");
    }

968
    if(vo.empty()) {
969
      throw UserSpecifiedAnEmptyStringVo("Cannot modify tape pool because the new VO is an empty string");
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
    }

    const time_t now = time(nullptr);
    const char *const sql =
      "UPDATE TAPE_POOL SET "
        "VO = :VO,"
        "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME,"
        "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME,"
        "LAST_UPDATE_TIME = :LAST_UPDATE_TIME "
      "WHERE "
        "TAPE_POOL_NAME = :TAPE_POOL_NAME";
    auto conn = m_connPool.getConn();
    auto stmt = conn.createStmt(sql, rdbms::AutocommitMode::ON);
    stmt.bindString(":VO", vo);
    stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username);
    stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host);
    stmt.bindUint64(":LAST_UPDATE_TIME", now);
    stmt.bindString(":TAPE_POOL_NAME", name);
    stmt.executeNonQuery();

    if(0 == stmt.getNbAffectedRows()) {
      throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist");
    }
  } catch(exception::UserError &) {
    throw;
  } catch(exception::Exception &ex) {
    ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
    throw;
  }
}

For faster browsing, not all history is shown. View entire blame