1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
|
//# TableUtil.cc: Utility functions for tables
//# Copyright (C) 2022
//# Associated Universities, Inc. Washington DC, USA.
//#
//# This library is free software; you can redistribute it and/or modify it
//# under the terms of the GNU Library General Public License as published by
//# the Free Software Foundation; either version 2 of the License, or (at your
//# option) any later version.
//#
//# This library 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 Library General Public
//# License for more details.
//#
//# You should have receied a copy of the GNU Library General Public License
//# along with this library; if not, write to the Free Software Foundation,
//# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
//#
//# Correspondence concerning AIPS++ should be addressed as follows:
//# Internet email: aips2-request@nrao.edu.
//# Postal address: AIPS++ Project Office
//# National Radio Astronomy Observatory
//# 520 Edgemont Road
//# Charlottesville, VA 22903-2475 USA
//#
//# $Id$
//# Includes
#include <casacore/tables/Tables/TableUtil.h>
#include <casacore/tables/Tables/SetupNewTab.h>
#include <casacore/tables/Tables/TableRecord.h>
#include <casacore/tables/Tables/TableAttr.h>
#include <casacore/tables/Tables/PlainTable.h>
#include <casacore/tables/Tables/RefTable.h>
#include <casacore/tables/Tables/ConcatTable.h>
#include <casacore/tables/Tables/TableError.h>
#include <casacore/casa/IO/ArrayIO.h>
#include <casacore/casa/OS/Path.h>
namespace casacore {
namespace TableUtil {
Table openTable (const String& tableName,
Table::TableOption option,
const TSMOption& tsmOption)
{
return openTable (tableName, TableLock(), option, tsmOption);
}
Table openTable (const String& tableName,
const TableLock& lockOpt,
Table::TableOption tabOpt,
const TSMOption& tsmOpt)
{
// See if the table can be opened as such.
if (Table::isReadable(tableName)) {
return Table(tableName, lockOpt, tabOpt, tsmOpt);
}
// Try to find and open the last subtable by splitting at ::
std::pair<Table,String> t(findParentTable(tableName, lockOpt, tabOpt, tsmOpt));
if (t.first.isNull()) {
// Note that tableName was already tried to be opened at beginning.
throw TableError ("Table " + tableName + " does not exist");
}
// Find the last subtable in the parent.
if (! t.first.keywordSet().isDefined(t.second)) {
throw TableError ("Table name " + tableName + " is invalid (" +
"subtable " + t.second + " is unknown)");
}
return t.first.keywordSet().asTable (t.second);
}
Table createTable (const String& tableName, const TableDesc& desc,
Table::TableOption tabOpt,
Table::TableType tabType,
const StorageOption& storageOption,
const Record& dmInfo,
const TableLock& lockOptions,
rownr_t nrrow, Bool initialize,
Table::EndianFormat endian,
const TSMOption& tsmOpt)
{
// Find and open the one but last subtable and get the name of the last one.
// An empty name results in a Scratch table.
std::pair<Table,String> t;
if (! tableName.empty()) {
t = findParentTable (tableName);
}
if (! t.second.empty()) {
return createSubTable (t.first, t.second, desc, tabOpt, storageOption,
dmInfo, lockOptions, nrrow, initialize, endian, tsmOpt);
} else {
// No subtable given, so create a main table.
SetupNewTable newtab(tableName, desc,
tableName.empty() ? Table::Scratch : tabOpt,
storageOption);
newtab.bindCreate (dmInfo);
// Create the table.
return Table(newtab, tabType, lockOptions, nrrow, initialize, endian, tsmOpt);
}
}
Table createSubTable (Table& parent, const String& subName,
const TableDesc& desc,
Table::TableOption tabOpt,
const StorageOption& storageOption,
const Record& dmInfo,
const TableLock& lockOptions,
rownr_t nrrow, Bool initialize,
Table::EndianFormat endian,
const TSMOption& tsmOpt)
{
// See if the subtable and its keyword already exist.
Int inx = parent.keywordSet().fieldNumber(subName);
if (inx >= 0) {
if (parent.keywordSet().type(inx) != TpTable) {
throw TableError("Subtable " + subName + " cannot be created in " +
parent.tableName() +
"; a keyword with that name already exists");
}
if (tabOpt == Table::NewNoReplace) {
throw TableError("Subtable " + parent.tableName() + '/' + subName +
" already exists");
}
// Remove the subtable.
deleteSubTable (parent, subName);
}
// Setup creation of the subtable and attach data managers.
SetupNewTable newtab(parent.tableName() + '/' + subName,
desc, tabOpt, storageOption);
newtab.bindCreate (dmInfo);
// Create the table and define the keyword for it in the parent.
Table subtab(newtab, lockOptions, nrrow, initialize, endian, tsmOpt);
parent.reopenRW();
parent.rwKeywordSet().defineTable (subName, subtab);
return subtab;
}
Bool canDeleteTable (const String& tableName, Bool checkSubTables)
{
String message;
return canDeleteTable (message, tableName, checkSubTables);
}
Bool canDeleteTable (String& message, const String& tableName,
Bool checkSubTables, Bool splitColons)
{
if (splitColons) {
std::pair<Table,String> t = findParentTable (tableName);
if (! t.first.isNull()) {
return canDeleteSubTable (message, t.first, t.second, checkSubTables);
}
}
String tabName = Path(tableName).absoluteName();
if (! Table::isWritable (tabName)) {
message = "table is not writable";
return False;
}
if (Table::isOpened (tabName)) {
message = "table is still open in this process";
return False;
}
Table table(tabName);
if (table.isMultiUsed()) {
message = "table is still open in another process";
return False;
}
if (checkSubTables && table.isMultiUsed(True)) {
message = "a subtable of the table is still open in another process";
return False;
}
return True;
}
Bool canDeleteSubTable (String& message, const Table& parent,
const String& subtableName,
Bool checkSubTables)
{
// Get the full table name of the subtable.
// Note: the temporary Table object is deleted before canDeleteTable.
// Otherwise isOpened() used internally would be true.
const String fullName (parent.keywordSet().asTable(subtableName).tableName());
return canDeleteTable (message, fullName, checkSubTables, False);
}
void deleteTable (const String& tableName, Bool checkSubTables)
{
// Check that the name is not empty, because making it absolute results in /
if (tableName.empty()) {
throw TableError
("Empty string provided for tableName; will not attempt delete.");
}
// See if the name represents a table.
if (! Table::isReadable(tableName)) {
// See if the name contains subtable names using ::
std::pair<Table,String> t = findParentTable (tableName);
if (! t.first.isNull()) {
deleteSubTable (t.first, t.second, checkSubTables);
return;
}
}
// Delete the table (which fails if it is not a table or still in use).
String tabName = Path(tableName).absoluteName();
String message;
if (! canDeleteTable (message, tabName, checkSubTables)) {
throw (TableError ("Table " + tabName + " cannot be deleted: " +
message));
}
Table table(tabName, Table::Delete);
}
void deleteSubTable (Table& parent, const String& subtableName, Bool checkSubTables)
{
String message;
if (! canDeleteSubTable (message, parent, subtableName, checkSubTables)) {
throw (TableError ("Subtable " + subtableName + " in " +
parent.tableName() + " cannot be deleted: " +
message));
}
Table subtab = parent.keywordSet().asTable(subtableName);
subtab.markForDelete();
// If there, remove the keyword referring the subtable.
Int inx = parent.keywordSet().fieldNumber(subtableName);
if (inx >= 0) {
if (parent.keywordSet().type(inx) == TpTable) {
parent.reopenRW();
parent.rwKeywordSet().removeField (subtableName);
}
}
}
//# The logic is similar to that in Table::open.
rownr_t getLayout (TableDesc& desc, const String& tableName)
{
rownr_t nrow;
uInt format;
String tp;
AipsIO ios (Table::fileName(getFullName(tableName)));
uInt version = ios.getstart ("Table");
if (version > 3) {
throw TableError ("Table version " + String::toString(version) +
" not supported by TableUtil in this version of Casacore");
}
if (version > 2) {
ios >> nrow;
} else {
uInt n;
ios >> n;
nrow = n;
}
ios >> format;
ios >> tp;
if (tp == "PlainTable") {
PlainTable::getLayout (desc, ios);
} else if (tp == "RefTable") {
RefTable::getLayout (desc, ios);
} else if (tp == "ConcatTable") {
ConcatTable::getLayout (desc, ios);
} else {
throw (TableInternalError
("TableUtil::getLayout: unknown table kind " + tp));
}
ios.close();
return nrow;
}
TableInfo tableInfo (const String& tableName)
{
return BaseTable::tableInfo (getFullName(tableName));
}
String getFullName (const String& tableName)
{
// See if a subtable is given using ::.
String tabName;
std::pair<Table,String> t = findParentTable (tableName);
if (t.first.isNull()) {
tabName = Path(tableName).absoluteName();
} else {
tabName = t.first.keywordSet().tableAttributes(t.second).name();
}
return tabName;
}
// Return Table and name of last part.
std::pair<Table,String> findParentTable (const String& fullName,
const TableLock& lockOpt,
Table::TableOption tabOpt,
const TSMOption& tsmOpt)
{
Table tab;
String lastPart, msg;
// Split the name on :: to get the main and subtable names.
const Vector<String> names = stringToVector(fullName, std::regex("::"));
AlwaysAssert (!names.empty(), AipsError);
// Check that no empty parts are given.
if (anyEQ (names, String())) {
msg = "empty name part given";
} else if (names.size() > 1) {
// Subtable given; check if previous parts exist.
// First check if main table exists.
if (! Table::isReadable (names[0])) {
msg = "main table " + names[0] + " does not exist";
} else {
tab = Table(names[0], lockOpt, tabOpt, tsmOpt);
// Get name of last subtable.
lastPart = names[names.size()-1];
// Check if all subtables exist, except last one.
for (uInt i=1; i<names.size()-1; ++i) {
if (! tab.keywordSet().isDefined(names[i])) {
msg = "subtable " + names[i] + " is unknown";
break;
}
tab = tab.keywordSet().asTable (names[i]);
}
}
}
if (! msg.empty()) {
throw TableError ("Table name " + fullName + " is invalid (" + msg + ')');
}
return std::make_pair (tab, lastPart);
}
} //# NAMESPACE TableUtil - END
} //# NAMESPACE CASACORE - END
|