1#coding:utf-8 2# 3# PROGRAM/MODULE: fdb 4# FILE: testfdb.py 5# DESCRIPTION: Python driver for Firebird - Unit tests 6# CREATED: 12.10.2011 7# 8# Software distributed under the License is distributed AS IS, 9# WITHOUT WARRANTY OF ANY KIND, either express or implied. 10# See the License for the specific language governing rights 11# and limitations under the License. 12# 13# The Original Code was created by Pavel Cisar 14# 15# Copyright (c) Pavel Cisar <pcisar@users.sourceforge.net> 16# and all contributors signed below. 17# 18# All Rights Reserved. 19# Contributor(s): Philippe Makowski <pmakowski@ibphoenix.fr> 20# ______________________________________. 21# 22# See LICENSE.TXT for details. 23 24import unittest 25import datetime, decimal, types 26import fdb 27import fdb.ibase as ibase 28import fdb.schema as sm 29import fdb.utils as utils 30import fdb.gstat as gstat 31import fdb.log as log 32import sys, os 33import threading 34import time 35import collections 36from decimal import Decimal 37from contextlib import closing 38from re import finditer 39from pprint import pprint 40from fdb.gstat import FillDistribution, Encryption, StatDatabase 41from fdb.log import LogEntry 42from locale import LC_ALL, getlocale, setlocale, getdefaultlocale 43 44if ibase.PYTHON_MAJOR_VER == 3: 45 from io import StringIO, BytesIO 46else: 47 from cStringIO import StringIO 48 BytesIO = StringIO 49 50FB20 = '2.0' 51FB21 = '2.1' 52FB25 = '2.5' 53FB30 = '3.0' 54 55# Default server host 56#FBTEST_HOST = '' 57FBTEST_HOST = 'localhost' 58# Default user 59FBTEST_USER = 'SYSDBA' 60# Default user password 61FBTEST_PASSWORD = 'masterkey' 62 63def linesplit_iter(string): 64 return (m.group(2) for m in finditer('((.*)\n|(.+)$)', string)) 65 66def get_object_data(obj, skip=[]): 67 def add(item): 68 if item not in skip: 69 value = getattr(obj, item) 70 if isinstance(value, collections.Sized) and isinstance(value, (collections.MutableSequence, collections.Mapping)): 71 value = len(value) 72 data[item] = value 73 74 data = {} 75 for item in utils.iter_class_variables(obj): 76 add(item) 77 for item in utils.iter_class_properties(obj): 78 add(item) 79 return data 80 81class SchemaVisitor(fdb.utils.Visitor): 82 def __init__(self, test, action, follow='dependencies'): 83 self.test = test 84 self.seen = [] 85 self.action = action 86 self.follow = follow 87 def default_action(self, obj): 88 if not obj.issystemobject() and self.action in obj.actions: 89 if self.follow == 'dependencies': 90 for dependency in obj.get_dependencies(): 91 d = dependency.depended_on 92 if d and d not in self.seen: 93 d.accept(self) 94 elif self.follow == 'dependents': 95 for dependency in obj.get_dependents(): 96 d = dependency.dependent 97 if d and d not in self.seen: 98 d.accept(self) 99 if obj not in self.seen: 100 self.test.printout(obj.get_sql_for(self.action)) 101 self.seen.append(obj) 102 def visit_TableColumn(self, column): 103 column.table.accept(self) 104 def visit_ViewColumn(self, column): 105 column.view.accept(self) 106 def visit_ProcedureParameter(self, param): 107 param.procedure.accept(self) 108 def visit_FunctionArgument(self, arg): 109 arg.function.accept(self) 110 111class FDBTestBase(unittest.TestCase): 112 def __init__(self, methodName='runTest'): 113 super(FDBTestBase, self).__init__(methodName) 114 self.output = StringIO() 115 def setUp(self): 116 with closing(fdb.services.connect(host=FBTEST_HOST, password=FBTEST_PASSWORD)) as svc: 117 self.version = svc.version 118 if self.version.startswith('2.0'): 119 self.FBTEST_DB = 'fbtest20.fdb' 120 self.version = FB20 121 elif self.version.startswith('2.1'): 122 self.FBTEST_DB = 'fbtest21.fdb' 123 self.version = FB21 124 elif self.version.startswith('2.5'): 125 self.FBTEST_DB = 'fbtest25.fdb' 126 self.version = FB25 127 elif self.version.startswith('3.0'): 128 self.FBTEST_DB = 'fbtest30.fdb' 129 self.version = FB30 130 else: 131 raise Exception("Unsupported Firebird version (%s)" % self.version) 132 # 133 self.cwd = os.getcwd() 134 self.dbpath = self.cwd if os.path.split(self.cwd)[1] == 'test' \ 135 else os.path.join(self.cwd, 'test') 136 def clear_output(self): 137 self.output.close() 138 self.output = StringIO() 139 def show_output(self): 140 sys.stdout.write(self.output.getvalue()) 141 sys.stdout.flush() 142 def printout(self, text='', newline=True, no_rstrip=False): 143 if no_rstrip: 144 self.output.write(text) 145 else: 146 self.output.write(text.rstrip()) 147 if newline: 148 self.output.write('\n') 149 self.output.flush() 150 def printData(self, cur, print_header=True): 151 """Print data from open cursor to stdout.""" 152 if print_header: 153 # Print a header. 154 line = [] 155 for fieldDesc in cur.description: 156 line.append(fieldDesc[fdb.DESCRIPTION_NAME].ljust(fieldDesc[fdb.DESCRIPTION_DISPLAY_SIZE])) 157 self.printout(' '.join(line)) 158 line = [] 159 for fieldDesc in cur.description: 160 line.append("-" * max((len(fieldDesc[fdb.DESCRIPTION_NAME]), fieldDesc[fdb.DESCRIPTION_DISPLAY_SIZE]))) 161 self.printout(' '.join(line)) 162 # For each row, print the value of each field left-justified within 163 # the maximum possible width of that field. 164 fieldIndices = range(len(cur.description)) 165 for row in cur: 166 line = [] 167 for fieldIndex in fieldIndices: 168 fieldValue = str(row[fieldIndex]) 169 fieldMaxWidth = max((len(cur.description[fieldIndex][fdb.DESCRIPTION_NAME]), cur.description[fieldIndex][fdb.DESCRIPTION_DISPLAY_SIZE])) 170 line.append(fieldValue.ljust(fieldMaxWidth)) 171 self.printout(' '.join(line)) 172 173class TestCreateDrop(FDBTestBase): 174 def setUp(self): 175 super(TestCreateDrop, self).setUp() 176 self.dbfile = os.path.join(self.dbpath, 'droptest.fdb') 177 if os.path.exists(self.dbfile): 178 os.remove(self.dbfile) 179 def test_create_drop(self): 180 with closing(fdb.create_database(host=FBTEST_HOST, database=self.dbfile, 181 user=FBTEST_USER, password=FBTEST_PASSWORD)) as con: 182 self.assertEqual(con.sql_dialect, 3) 183 self.assertEqual(con.charset, None) 184 con.drop_database() 185 # 186 with closing(fdb.create_database(host=FBTEST_HOST, port=3050, database=self.dbfile, 187 user=FBTEST_USER, password=FBTEST_PASSWORD)) as con: 188 self.assertEqual(con.sql_dialect, 3) 189 self.assertEqual(con.charset, None) 190 con.drop_database() 191 # 192 with closing(fdb.create_database(host=FBTEST_HOST, database=self.dbfile, 193 user=FBTEST_USER, password=FBTEST_PASSWORD, 194 sql_dialect=1, charset='UTF8')) as con: 195 self.assertEqual(con.sql_dialect, 1) 196 self.assertEqual(con.charset, 'UTF8') 197 con.drop_database() 198 199class TestConnection(FDBTestBase): 200 def setUp(self): 201 super(TestConnection, self).setUp() 202 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 203 def tearDown(self): 204 pass 205 def test_connect(self): 206 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) as con: 207 self.assertIsNotNone(con._db_handle) 208 dpb = [1, 0x1c, len(FBTEST_USER)] 209 dpb.extend(ord(x) for x in FBTEST_USER) 210 dpb.extend((0x1d, len(FBTEST_PASSWORD))) 211 dpb.extend(ord(x) for x in FBTEST_PASSWORD) 212 dpb.extend((ord('?'), 1, 3)) 213 self.assertEqual(con._dpb, fdb.bs(dpb)) 214 with fdb.connect(database=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) as con: 215 self.assertIsNotNone(con._db_handle) 216 with fdb.connect(port=3050, database=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) as con: 217 self.assertIsNotNone(con._db_handle) 218 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD, 219 no_gc=1, no_db_triggers=1) as con: 220 dpb.extend([ibase.isc_dpb_no_garbage_collect, 1, 1]) 221 dpb.extend([ibase.isc_dpb_no_db_triggers, 1, 1]) 222 self.assertEqual(con._dpb, fdb.bs(dpb)) 223 # UTF-8 filenames (FB 2.5+) 224 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD, utf8params=True) as con: 225 self.assertIsNotNone(con._db_handle) 226 dpb = [1, 0x1c, len(FBTEST_USER)] 227 dpb.extend(ord(x) for x in FBTEST_USER) 228 dpb.extend((0x1d, len(FBTEST_PASSWORD))) 229 dpb.extend(ord(x) for x in FBTEST_PASSWORD) 230 dpb.extend((ord('?'), 1, 3)) 231 dpb.extend((77, 1, 1)) 232 self.assertEqual(con._dpb, fdb.bs(dpb)) 233 def test_properties(self): 234 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) as con: 235 self.assertIn('Firebird', con.server_version) 236 self.assertIn('Firebird', con.firebird_version) 237 self.assertIsInstance(con.version, str) 238 self.assertGreaterEqual(con.engine_version, 2.0) 239 self.assertGreaterEqual(con.ods, 11.0) 240 self.assertIsNone(con.group) 241 self.assertIsNone(con.charset) 242 self.assertEqual(len(con.transactions), 2) 243 self.assertIn(con.main_transaction, con.transactions) 244 self.assertIn(con.query_transaction, con.transactions) 245 self.assertEqual(con.default_tpb, fdb.ISOLATION_LEVEL_READ_COMMITED) 246 self.assertIsInstance(con.schema, sm.Schema) 247 self.assertFalse(con.closed) 248 def test_connect_role(self): 249 rolename = 'role' 250 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, 251 password=FBTEST_PASSWORD, role=rolename) as con: 252 self.assertIsNotNone(con._db_handle) 253 dpb = [1, 0x1c, len(FBTEST_USER)] 254 dpb.extend(ord(x) for x in FBTEST_USER) 255 dpb.extend((0x1d, len(FBTEST_PASSWORD))) 256 dpb.extend(ord(x) for x in FBTEST_PASSWORD) 257 dpb.extend((ord('<'), len(rolename))) 258 dpb.extend(ord(x) for x in rolename) 259 dpb.extend((ord('?'), 1, 3)) 260 self.assertEqual(con._dpb, fdb.bs(dpb)) 261 def test_transaction(self): 262 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) as con: 263 self.assertIsNotNone(con.main_transaction) 264 self.assertFalse(con.main_transaction.active) 265 self.assertFalse(con.main_transaction.closed) 266 self.assertEqual(con.main_transaction.default_action, 'commit') 267 self.assertEqual(len(con.main_transaction._connections), 1) 268 self.assertEqual(con.main_transaction._connections[0](), con) 269 con.begin() 270 self.assertFalse(con.main_transaction.closed) 271 con.commit() 272 self.assertFalse(con.main_transaction.active) 273 con.begin() 274 con.rollback() 275 self.assertFalse(con.main_transaction.active) 276 con.begin() 277 con.commit(retaining=True) 278 self.assertTrue(con.main_transaction.active) 279 con.rollback(retaining=True) 280 self.assertTrue(con.main_transaction.active) 281 tr = con.trans() 282 self.assertIsInstance(tr, fdb.Transaction) 283 self.assertFalse(con.main_transaction.closed) 284 self.assertEqual(len(con.transactions), 3) 285 tr.begin() 286 self.assertFalse(tr.closed) 287 con.begin() 288 con.close() 289 self.assertFalse(con.main_transaction.active) 290 self.assertTrue(con.main_transaction.closed) 291 self.assertFalse(tr.active) 292 self.assertTrue(tr.closed) 293 def test_execute_immediate(self): 294 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) as con: 295 con.execute_immediate("recreate table t (c1 integer)") 296 con.commit() 297 con.execute_immediate("delete from t") 298 con.commit() 299 def test_database_info(self): 300 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) as con: 301 self.assertEqual(con.database_info(fdb.isc_info_db_read_only, 'i'), 0) 302 if con.ods < fdb.ODS_FB_30: 303 self.assertEqual(con.database_info(fdb.isc_info_page_size, 'i'), 4096) 304 else: 305 self.assertEqual(con.database_info(fdb.isc_info_page_size, 'i'), 8192) 306 self.assertEqual(con.database_info(fdb.isc_info_db_sql_dialect, 'i'), 3) 307 def test_db_info(self): 308 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) as con: 309 with con.trans() as t1, con.trans() as t2: 310 self.assertListEqual(con.db_info(fdb.isc_info_active_transactions), []) 311 t1.begin() 312 t2.begin() 313 self.assertListEqual(con.db_info(fdb.isc_info_active_transactions), 314 [t1.transaction_id, t2.transaction_id]) 315 # 316 self.assertEqual(len(con.get_page_contents(0)), con.page_size) 317 # 318 res = con.db_info([fdb.isc_info_page_size, fdb.isc_info_db_read_only, 319 fdb.isc_info_db_sql_dialect, fdb.isc_info_user_names]) 320 if con.ods < fdb.ODS_FB_30: 321 self.assertDictEqual(res, {53: {'SYSDBA': 1}, 62: 3, 14: 4096, 63: 0}) 322 else: 323 self.assertDictEqual(res, {53: {'SYSDBA': 1}, 62: 3, 14: 8192, 63: 0}) 324 res = con.db_info(fdb.isc_info_read_seq_count) 325 if con.ods < fdb.ODS_FB_30: 326 self.assertDictEqual(res, {0: 98, 1: 1}) 327 else: 328 self.assertDictEqual(res, {0: 106, 1: 2}) 329 # 330 self.assertIsInstance(con.db_info(fdb.isc_info_allocation), int) 331 self.assertIsInstance(con.db_info(fdb.isc_info_base_level), int) 332 res = con.db_info(fdb.isc_info_db_id) 333 self.assertIsInstance(res, tuple) 334 self.assertEqual(res[0].upper(), self.dbfile.upper()) 335 res = con.db_info(ibase.isc_info_implementation) 336 self.assertIsInstance(res, tuple) 337 self.assertEqual(len(res), 2) 338 self.assertIsInstance(res[0], int) 339 self.assertIsInstance(res[1], int) 340 self.assertNotEqual(fdb.IMPLEMENTATION_NAMES.get(res[0], 'Unknown'), 'Unknown') 341 self.assertIn('Firebird', con.db_info(fdb.isc_info_version)) 342 self.assertIn('Firebird', con.db_info(fdb.isc_info_firebird_version)) 343 self.assertIn(con.db_info(fdb.isc_info_no_reserve), (0, 1)) 344 self.assertIn(con.db_info(fdb.isc_info_forced_writes), (0, 1)) 345 self.assertIsInstance(con.db_info(fdb.isc_info_base_level), int) 346 self.assertIsInstance(con.db_info(fdb.isc_info_ods_version), int) 347 self.assertIsInstance(con.db_info(fdb.isc_info_ods_minor_version), int) 348 349 def test_info_attributes(self): 350 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) as con: 351 self.assertGreater(con.attachment_id, 0) 352 self.assertEqual(con.sql_dialect, 3) 353 self.assertEqual(con.database_sql_dialect, 3) 354 self.assertEqual(con.database_name.upper(), self.dbfile.upper()) 355 self.assertIsInstance(con.site_name, str) 356 self.assertIn(con.implementation_id, fdb.IMPLEMENTATION_NAMES.keys()) 357 self.assertIn(con.provider_id, fdb.PROVIDER_NAMES.keys()) 358 self.assertIn(con.db_class_id, fdb.DB_CLASS_NAMES.keys()) 359 self.assertIsInstance(con.creation_date, datetime.datetime) 360 self.assertIn(con.page_size, [4096, 8192, 16384]) 361 self.assertEqual(con.sweep_interval, 20000) 362 self.assertTrue(con.space_reservation) 363 self.assertTrue(con.forced_writes) 364 self.assertGreater(con.current_memory, 0) 365 self.assertGreater(con.max_memory, 0) 366 self.assertGreater(con.oit, 0) 367 self.assertGreater(con.oat, 0) 368 self.assertGreater(con.ost, 0) 369 self.assertGreater(con.next_transaction, 0) 370 self.assertFalse(con.isreadonly()) 371 # 372 io = con.io_stats 373 self.assertEqual(len(io), 4) 374 self.assertIsInstance(io, dict) 375 s = con.get_table_access_stats() 376 self.assertEqual(len(s), 6) 377 self.assertIsInstance(s[0], fdb.fbcore._TableAccessStats) 378 # 379 with con.trans() as t1, con.trans() as t2: 380 self.assertListEqual(con.get_active_transaction_ids(), []) 381 t1.begin() 382 t2.begin() 383 self.assertListEqual(con.get_active_transaction_ids(), 384 [t1.transaction_id, t2.transaction_id]) 385 self.assertEqual(con.get_active_transaction_count(), 2) 386 387class TestTransaction(FDBTestBase): 388 def setUp(self): 389 super(TestTransaction, self).setUp() 390 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 391 self.con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 392 user=FBTEST_USER, password=FBTEST_PASSWORD) 393 #self.con.execute_immediate("recreate table t (c1 integer)") 394 #self.con.commit() 395 def tearDown(self): 396 self.con.execute_immediate("delete from t") 397 self.con.commit() 398 self.con.close() 399 def test_cursor(self): 400 tr = self.con.main_transaction 401 tr.begin() 402 cur = tr.cursor() 403 cur.execute("insert into t (c1) values (1)") 404 tr.commit() 405 cur.execute("select * from t") 406 rows = cur.fetchall() 407 self.assertListEqual(rows, [(1,)]) 408 cur.execute("delete from t") 409 tr.commit() 410 self.assertEqual(len(tr.cursors), 1) 411 self.assertIs(tr.cursors[0], cur) 412 def test_context_manager(self): 413 with fdb.TransactionContext(self.con) as tr: 414 cur = tr.cursor() 415 cur.execute("insert into t (c1) values (1)") 416 417 cur.execute("select * from t") 418 rows = cur.fetchall() 419 self.assertListEqual(rows, [(1,)]) 420 421 try: 422 with fdb.TransactionContext(self.con) as tr: 423 cur.execute("delete from t") 424 raise Exception() 425 except Exception as e: 426 pass 427 428 cur.execute("select * from t") 429 rows = cur.fetchall() 430 self.assertListEqual(rows, [(1,)]) 431 432 with fdb.TransactionContext(self.con) as tr: 433 cur.execute("delete from t") 434 435 cur.execute("select * from t") 436 rows = cur.fetchall() 437 self.assertListEqual(rows, []) 438 def test_savepoint(self): 439 self.con.begin() 440 tr = self.con.main_transaction 441 self.con.execute_immediate("insert into t (c1) values (1)") 442 tr.savepoint('test') 443 self.con.execute_immediate("insert into t (c1) values (2)") 444 tr.rollback(savepoint='test') 445 tr.commit() 446 cur = tr.cursor() 447 cur.execute("select * from t") 448 rows = cur.fetchall() 449 self.assertListEqual(rows, [(1,)]) 450 def test_fetch_after_commit(self): 451 self.con.execute_immediate("insert into t (c1) values (1)") 452 self.con.commit() 453 cur = self.con.cursor() 454 cur.execute("select * from t") 455 self.con.commit() 456 with self.assertRaises(fdb.DatabaseError) as cm: 457 rows = cur.fetchall() 458 self.assertTupleEqual(cm.exception.args, ('Cannot fetch from this cursor because it has not executed a statement.',)) 459 def test_fetch_after_rollback(self): 460 self.con.execute_immediate("insert into t (c1) values (1)") 461 self.con.rollback() 462 cur = self.con.cursor() 463 cur.execute("select * from t") 464 self.con.commit() 465 with self.assertRaises(fdb.DatabaseError) as cm: 466 rows = cur.fetchall() 467 self.assertTupleEqual(cm.exception.args, ('Cannot fetch from this cursor because it has not executed a statement.',)) 468 def test_tpb(self): 469 tpb = fdb.TPB() 470 tpb.access_mode = fdb.isc_tpb_write 471 tpb.isolation_level = fdb.isc_tpb_read_committed 472 tpb.isolation_level = (fdb.isc_tpb_read_committed, fdb.isc_tpb_rec_version) 473 tpb.lock_resolution = fdb.isc_tpb_wait 474 tpb.lock_timeout = 10 475 tpb.table_reservation['COUNTRY'] = (fdb.isc_tpb_protected, fdb.isc_tpb_lock_write) 476 tr = self.con.trans(tpb) 477 tr.begin() 478 tr.commit() 479 def test_transaction_info(self): 480 self.con.begin() 481 tr = self.con.main_transaction 482 info = tr.transaction_info(ibase.isc_info_tra_isolation, 'b') 483 self.assertEqual(info, ibase.b('\x08\x02\x00\x03\x01')) 484 # 485 self.assertGreater(tr.transaction_id, 0) 486 self.assertGreater(tr.oit, 0) 487 self.assertGreater(tr.oat, 0) 488 self.assertGreater(tr.ost, 0) 489 self.assertEqual(tr.lock_timeout, -1) 490 self.assertTupleEqual(tr.isolation, (3, 1)) 491 tr.commit() 492 493class TestDistributedTransaction(FDBTestBase): 494 def setUp(self): 495 super(TestDistributedTransaction, self).setUp() 496 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 497 self.db1 = os.path.join(self.dbpath, 'fbtest-1.fdb') 498 self.db2 = os.path.join(self.dbpath, 'fbtest-2.fdb') 499 if not os.path.exists(self.db1): 500 self.con1 = fdb.create_database(host=FBTEST_HOST, database=self.db1, 501 user=FBTEST_USER, 502 password=FBTEST_PASSWORD) 503 else: 504 self.con1 = fdb.connect(host=FBTEST_HOST, database=self.db1, 505 user=FBTEST_USER, password=FBTEST_PASSWORD) 506 self.con1.execute_immediate("recreate table T (PK integer, C1 integer)") 507 self.con1.commit() 508 if not os.path.exists(self.db2): 509 self.con2 = fdb.create_database(host=FBTEST_HOST, database=self.db2, 510 user=FBTEST_USER, 511 password=FBTEST_PASSWORD) 512 else: 513 self.con2 = fdb.connect(host=FBTEST_HOST, database=self.db2, 514 user=FBTEST_USER, password=FBTEST_PASSWORD) 515 self.con2.execute_immediate("recreate table T (PK integer, C1 integer)") 516 self.con2.commit() 517 def tearDown(self): 518 if self.con1 and self.con1.group: 519 # We can't drop database via connection in group 520 self.con1.group.disband() 521 if not self.con1: 522 self.con1 = fdb.connect(host=FBTEST_HOST, database=self.db1, 523 user=FBTEST_USER, password=FBTEST_PASSWORD) 524 self.con1.drop_database() 525 self.con1.close() 526 if not self.con2: 527 self.con2 = fdb.connect(host=FBTEST_HOST, database=self.db2, 528 user=FBTEST_USER, password=FBTEST_PASSWORD) 529 self.con2.drop_database() 530 self.con2.close() 531 def test_context_manager(self): 532 cg = fdb.ConnectionGroup((self.con1, self.con2)) 533 534 q = 'select * from T order by pk' 535 c1 = cg.cursor(self.con1) 536 cc1 = self.con1.cursor() 537 p1 = cc1.prep(q) 538 539 c2 = cg.cursor(self.con2) 540 cc2 = self.con2.cursor() 541 p2 = cc2.prep(q) 542 543 # Distributed transaction: COMMIT 544 with fdb.TransactionContext(cg): 545 c1.execute('insert into t (pk) values (1)') 546 c2.execute('insert into t (pk) values (1)') 547 548 self.con1.commit() 549 cc1.execute(p1) 550 result = cc1.fetchall() 551 self.assertListEqual(result, [(1, None)]) 552 self.con2.commit() 553 cc2.execute(p2) 554 result = cc2.fetchall() 555 self.assertListEqual(result, [(1, None)]) 556 557 # Distributed transaction: ROLLBACK 558 try: 559 with fdb.TransactionContext(cg): 560 c1.execute('insert into t (pk) values (2)') 561 c2.execute('insert into t (pk) values (2)') 562 raise Exception() 563 except Exception as e: 564 pass 565 566 c1.execute(q) 567 result = c1.fetchall() 568 self.assertListEqual(result, [(1, None)]) 569 c2.execute(q) 570 result = c2.fetchall() 571 self.assertListEqual(result, [(1, None)]) 572 573 cg.disband() 574 575 def test_simple_dt(self): 576 cg = fdb.ConnectionGroup((self.con1, self.con2)) 577 self.assertEqual(self.con1.group, cg) 578 self.assertEqual(self.con2.group, cg) 579 580 q = 'select * from T order by pk' 581 c1 = cg.cursor(self.con1) 582 cc1 = self.con1.cursor() 583 p1 = cc1.prep(q) 584 585 c2 = cg.cursor(self.con2) 586 cc2 = self.con2.cursor() 587 p2 = cc2.prep(q) 588 589 # Distributed transaction: COMMIT 590 c1.execute('insert into t (pk) values (1)') 591 c2.execute('insert into t (pk) values (1)') 592 cg.commit() 593 594 self.con1.commit() 595 cc1.execute(p1) 596 result = cc1.fetchall() 597 self.assertListEqual(result, [(1, None)]) 598 self.con2.commit() 599 cc2.execute(p2) 600 result = cc2.fetchall() 601 self.assertListEqual(result, [(1, None)]) 602 603 # Distributed transaction: PREPARE+COMMIT 604 c1.execute('insert into t (pk) values (2)') 605 c2.execute('insert into t (pk) values (2)') 606 cg.prepare() 607 cg.commit() 608 609 self.con1.commit() 610 cc1.execute(p1) 611 result = cc1.fetchall() 612 self.assertListEqual(result, [(1, None), (2, None)]) 613 self.con2.commit() 614 cc2.execute(p2) 615 result = cc2.fetchall() 616 self.assertListEqual(result, [(1, None), (2, None)]) 617 618 # Distributed transaction: SAVEPOINT+ROLLBACK to it 619 c1.execute('insert into t (pk) values (3)') 620 cg.savepoint('CG_SAVEPOINT') 621 c2.execute('insert into t (pk) values (3)') 622 cg.rollback(savepoint='CG_SAVEPOINT') 623 624 c1.execute(q) 625 result = c1.fetchall() 626 self.assertListEqual(result, [(1, None), (2, None), (3, None)]) 627 c2.execute(q) 628 result = c2.fetchall() 629 self.assertListEqual(result, [(1, None), (2, None)]) 630 631 # Distributed transaction: ROLLBACK 632 cg.rollback() 633 634 self.con1.commit() 635 cc1.execute(p1) 636 result = cc1.fetchall() 637 self.assertListEqual(result, [(1, None), (2, None)]) 638 self.con2.commit() 639 cc2.execute(p2) 640 result = cc2.fetchall() 641 self.assertListEqual(result, [(1, None), (2, None)]) 642 643 # Distributed transaction: EXECUTE_IMMEDIATE 644 cg.execute_immediate('insert into t (pk) values (3)') 645 cg.commit() 646 647 self.con1.commit() 648 cc1.execute(p1) 649 result = cc1.fetchall() 650 self.assertListEqual(result, [(1, None), (2, None), (3, None)]) 651 self.con2.commit() 652 cc2.execute(p2) 653 result = cc2.fetchall() 654 self.assertListEqual(result, [(1, None), (2, None), (3, None)]) 655 656 cg.disband() 657 self.assertIsNone(self.con1.group) 658 self.assertIsNone(self.con2.group) 659 def test_limbo_transactions(self): 660 return 661 cg = fdb.ConnectionGroup((self.con1, self.con2)) 662 svc = fdb.services.connect(host=FBTEST_HOST, password=FBTEST_PASSWORD) 663 664 ids1 = svc.get_limbo_transaction_ids(self.db1) 665 self.assertEqual(ids1, []) 666 ids2 = svc.get_limbo_transaction_ids(self.db2) 667 self.assertEqual(ids2, []) 668 669 cg.execute_immediate('insert into t (pk) values (3)') 670 cg.prepare() 671 672 # Force out both connections 673 self.con1._set_group(None) 674 cg._cons.remove(self.con1) 675 del self.con1 676 self.con1 = None 677 678 self.con2._set_group(None) 679 cg._cons.remove(self.con2) 680 del self.con2 681 self.con2 = None 682 683 # Disband will raise an error 684 with self.assertRaises(fdb.DatabaseError) as cm: 685 cg.disband() 686 self.assertTupleEqual(cm.exception.args, 687 ('Error while rolling back transaction:\n- SQLCODE: -901\n- invalid transaction handle (expecting explicit transaction start)', -901, 335544332)) 688 689 ids1 = svc.get_limbo_transaction_ids(self.db1) 690 id1 = ids1[0] 691 ids2 = svc.get_limbo_transaction_ids(self.db2) 692 id2 = ids2[0] 693 694 # Data chould be blocked by limbo transaction 695 if not self.con1: 696 self.con1 = fdb.connect(dsn=self.db1, user=FBTEST_USER, 697 password=FBTEST_PASSWORD) 698 if not self.con2: 699 self.con2 = fdb.connect(dsn=self.db2, user=FBTEST_USER, 700 password=FBTEST_PASSWORD) 701 c1 = self.con1.cursor() 702 c1.execute('select * from t') 703 with self.assertRaises(fdb.DatabaseError) as cm: 704 row = c1.fetchall() 705 self.assertTupleEqual(cm.exception.args, 706 ('Cursor.fetchone:\n- SQLCODE: -911\n- record from transaction %i is stuck in limbo' % id1, -911, 335544459)) 707 c2 = self.con2.cursor() 708 c2.execute('select * from t') 709 with self.assertRaises(fdb.DatabaseError) as cm: 710 row = c2.fetchall() 711 self.assertTupleEqual(cm.exception.args, 712 ('Cursor.fetchone:\n- SQLCODE: -911\n- record from transaction %i is stuck in limbo' % id2, -911, 335544459)) 713 714 # resolve via service 715 svc = fdb.services.connect(host=FBTEST_HOST, password=FBTEST_PASSWORD) 716 svc.commit_limbo_transaction(self.db1, id1) 717 svc.rollback_limbo_transaction(self.db2, id2) 718 719 # check the resolution 720 c1 = self.con1.cursor() 721 c1.execute('select * from t') 722 row = c1.fetchall() 723 self.assertListEqual(row, [(3, None)]) 724 c2 = self.con2.cursor() 725 c2.execute('select * from t') 726 row = c2.fetchall() 727 self.assertListEqual(row, []) 728 729 svc.close() 730 731class TestCursor(FDBTestBase): 732 def setUp(self): 733 super(TestCursor, self).setUp() 734 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 735 self.con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 736 user=FBTEST_USER, password=FBTEST_PASSWORD) 737 self.con.execute_immediate("recreate table t (c1 integer primary key)") 738 self.con.commit() 739 def tearDown(self): 740 self.con.execute_immediate("delete from t") 741 self.con.commit() 742 self.con.close() 743 def test_executemany(self): 744 cur = self.con.cursor() 745 cur.executemany("insert into t values(?)", [(1,), (2,)]) 746 cur.executemany("insert into t values(?)", [(3,)]) 747 cur.executemany("insert into t values(?)", [(4,), (5,), (6,)]) 748 self.con.commit() 749 p = cur.prep("insert into t values(?)") 750 cur.executemany(p, [(7,), (8,)]) 751 cur.executemany(p, [(9,)]) 752 cur.executemany(p, [(10,), (11,), (12,)]) 753 self.con.commit() 754 cur.execute("select * from T order by c1") 755 rows = cur.fetchall() 756 self.assertListEqual(rows, [(1,), (2,), (3,), (4,), 757 (5,), (6,), (7,), (8,), 758 (9,), (10,), (11,), (12,)]) 759 def test_iteration(self): 760 if self.con.ods < fdb.ODS_FB_30: 761 data = [('USA', 'Dollar'), ('England', 'Pound'), ('Canada', 'CdnDlr'), 762 ('Switzerland', 'SFranc'), ('Japan', 'Yen'), ('Italy', 'Lira'), 763 ('France', 'FFranc'), ('Germany', 'D-Mark'), ('Australia', 'ADollar'), 764 ('Hong Kong', 'HKDollar'), ('Netherlands', 'Guilder'), 765 ('Belgium', 'BFranc'), ('Austria', 'Schilling'), ('Fiji', 'FDollar')] 766 else: 767 data = [('USA', 'Dollar'), ('England', 'Pound'), ('Canada', 'CdnDlr'), 768 ('Switzerland', 'SFranc'), ('Japan', 'Yen'), ('Italy', 'Euro'), 769 ('France', 'Euro'), ('Germany', 'Euro'), ('Australia', 'ADollar'), 770 ('Hong Kong', 'HKDollar'), ('Netherlands', 'Euro'), ('Belgium', 'Euro'), 771 ('Austria', 'Euro'), ('Fiji', 'FDollar'), ('Russia', 'Ruble'), 772 ('Romania', 'RLeu')] 773 cur = self.con.cursor() 774 cur.execute('select * from country') 775 rows = [row for row in cur] 776 self.assertEqual(len(rows), len(data)) 777 self.assertListEqual(rows, data) 778 cur.execute('select * from country') 779 rows = [] 780 for row in cur: 781 rows.append(row) 782 self.assertEqual(len(rows), len(data)) 783 self.assertListEqual(rows, data) 784 cur.execute('select * from country') 785 i = 0 786 for row in cur: 787 i += 1 788 self.assertIn(row, data) 789 self.assertEqual(i, len(data)) 790 def test_description(self): 791 cur = self.con.cursor() 792 cur.execute('select * from country') 793 self.assertEqual(len(cur.description), 2) 794 if ibase.PYTHON_MAJOR_VER == 3: 795 self.assertEqual(repr(cur.description), 796 "(('COUNTRY', <class 'str'>, 15, 15, 0, 0, False), " \ 797 "('CURRENCY', <class 'str'>, 10, 10, 0, 0, False))") 798 else: 799 self.assertEqual(repr(cur.description), 800 "(('COUNTRY', <type 'str'>, 15, 15, 0, 0, False), " \ 801 "('CURRENCY', <type 'str'>, 10, 10, 0, 0, False))") 802 cur.execute('select country as CT, currency as CUR from country') 803 self.assertEqual(len(cur.description), 2) 804 cur.execute('select * from customer') 805 if ibase.PYTHON_MAJOR_VER == 3: 806 self.assertEqual(repr(cur.description), 807 "(('CUST_NO', <class 'int'>, 11, 4, 0, 0, False), " \ 808 "('CUSTOMER', <class 'str'>, 25, 25, 0, 0, False), " \ 809 "('CONTACT_FIRST', <class 'str'>, 15, 15, 0, 0, True), " \ 810 "('CONTACT_LAST', <class 'str'>, 20, 20, 0, 0, True), " \ 811 "('PHONE_NO', <class 'str'>, 20, 20, 0, 0, True), " \ 812 "('ADDRESS_LINE1', <class 'str'>, 30, 30, 0, 0, True), " \ 813 "('ADDRESS_LINE2', <class 'str'>, 30, 30, 0, 0, True), " \ 814 "('CITY', <class 'str'>, 25, 25, 0, 0, True), " \ 815 "('STATE_PROVINCE', <class 'str'>, 15, 15, 0, 0, True), " \ 816 "('COUNTRY', <class 'str'>, 15, 15, 0, 0, True), " \ 817 "('POSTAL_CODE', <class 'str'>, 12, 12, 0, 0, True), " \ 818 "('ON_HOLD', <class 'str'>, 1, 1, 0, 0, True))") 819 else: 820 self.assertEqual(repr(cur.description), 821 "(('CUST_NO', <type 'int'>, 11, 4, 0, 0, False), " \ 822 "('CUSTOMER', <type 'str'>, 25, 25, 0, 0, False), " \ 823 "('CONTACT_FIRST', <type 'str'>, 15, 15, 0, 0, True), " \ 824 "('CONTACT_LAST', <type 'str'>, 20, 20, 0, 0, True), " \ 825 "('PHONE_NO', <type 'str'>, 20, 20, 0, 0, True), " \ 826 "('ADDRESS_LINE1', <type 'str'>, 30, 30, 0, 0, True), " \ 827 "('ADDRESS_LINE2', <type 'str'>, 30, 30, 0, 0, True), " \ 828 "('CITY', <type 'str'>, 25, 25, 0, 0, True), " \ 829 "('STATE_PROVINCE', <type 'str'>, 15, 15, 0, 0, True), " \ 830 "('COUNTRY', <type 'str'>, 15, 15, 0, 0, True), " \ 831 "('POSTAL_CODE', <type 'str'>, 12, 12, 0, 0, True), " \ 832 "('ON_HOLD', <type 'str'>, 1, 1, 0, 0, True))") 833 cur.execute('select * from job') 834 if ibase.PYTHON_MAJOR_VER == 3: 835 self.assertEqual(repr(cur.description), 836 "(('JOB_CODE', <class 'str'>, 5, 5, 0, 0, False), " \ 837 "('JOB_GRADE', <class 'int'>, 6, 2, 0, 0, False), " \ 838 "('JOB_COUNTRY', <class 'str'>, 15, 15, 0, 0, False), " \ 839 "('JOB_TITLE', <class 'str'>, 25, 25, 0, 0, False), " \ 840 "('MIN_SALARY', <class 'decimal.Decimal'>, 20, 8, 10, -2, False), " \ 841 "('MAX_SALARY', <class 'decimal.Decimal'>, 20, 8, 10, -2, False), " \ 842 "('JOB_REQUIREMENT', <class 'str'>, 0, 8, 0, 1, True), " \ 843 "('LANGUAGE_REQ', <class 'list'>, -1, 8, 0, 0, True))") 844 else: 845 self.assertEqual(repr(cur.description), 846 "(('JOB_CODE', <type 'str'>, 5, 5, 0, 0, False), " \ 847 "('JOB_GRADE', <type 'int'>, 6, 2, 0, 0, False), " \ 848 "('JOB_COUNTRY', <type 'str'>, 15, 15, 0, 0, False), " \ 849 "('JOB_TITLE', <type 'str'>, 25, 25, 0, 0, False), " \ 850 "('MIN_SALARY', <class 'decimal.Decimal'>, 20, 8, 10, -2, False), " \ 851 "('MAX_SALARY', <class 'decimal.Decimal'>, 20, 8, 10, -2, False), " \ 852 "('JOB_REQUIREMENT', <type 'str'>, 0, 8, 0, 1, True), " \ 853 "('LANGUAGE_REQ', <type 'list'>, -1, 8, 0, 0, True))") 854 cur.execute('select * from proj_dept_budget') 855 if ibase.PYTHON_MAJOR_VER == 3: 856 self.assertEqual(repr(cur.description), 857 "(('FISCAL_YEAR', <class 'int'>, 11, 4, 0, 0, False), " \ 858 "('PROJ_ID', <class 'str'>, 5, 5, 0, 0, False), " \ 859 "('DEPT_NO', <class 'str'>, 3, 3, 0, 0, False), " \ 860 "('QUART_HEAD_CNT', <class 'list'>, -1, 8, 0, 0, True), " \ 861 "('PROJECTED_BUDGET', <class 'decimal.Decimal'>, 20, 8, 12, -2, True))") 862 else: 863 self.assertEqual(repr(cur.description), 864 "(('FISCAL_YEAR', <type 'int'>, 11, 4, 0, 0, False), " \ 865 "('PROJ_ID', <type 'str'>, 5, 5, 0, 0, False), " \ 866 "('DEPT_NO', <type 'str'>, 3, 3, 0, 0, False), " \ 867 "('QUART_HEAD_CNT', <type 'list'>, -1, 8, 0, 0, True), " \ 868 "('PROJECTED_BUDGET', <class 'decimal.Decimal'>, 20, 8, 12, -2, True))") 869 # Check for precision cache 870 cur2 = self.con.cursor() 871 cur2.execute('select * from proj_dept_budget') 872 if ibase.PYTHON_MAJOR_VER == 3: 873 self.assertEqual(repr(cur2.description), 874 "(('FISCAL_YEAR', <class 'int'>, 11, 4, 0, 0, False), " \ 875 "('PROJ_ID', <class 'str'>, 5, 5, 0, 0, False), " \ 876 "('DEPT_NO', <class 'str'>, 3, 3, 0, 0, False), " \ 877 "('QUART_HEAD_CNT', <class 'list'>, -1, 8, 0, 0, True), " \ 878 "('PROJECTED_BUDGET', <class 'decimal.Decimal'>, 20, 8, 12, -2, True))") 879 else: 880 self.assertEqual(repr(cur2.description), 881 "(('FISCAL_YEAR', <type 'int'>, 11, 4, 0, 0, False), " \ 882 "('PROJ_ID', <type 'str'>, 5, 5, 0, 0, False), " \ 883 "('DEPT_NO', <type 'str'>, 3, 3, 0, 0, False), " \ 884 "('QUART_HEAD_CNT', <type 'list'>, -1, 8, 0, 0, True), " \ 885 "('PROJECTED_BUDGET', <class 'decimal.Decimal'>, 20, 8, 12, -2, True))") 886 def test_exec_after_close(self): 887 cur = self.con.cursor() 888 cur.execute('select * from country') 889 row = cur.fetchone() 890 self.assertTupleEqual(row, ('USA', 'Dollar')) 891 cur.close() 892 cur.execute('select * from country') 893 row = cur.fetchone() 894 self.assertTupleEqual(row, ('USA', 'Dollar')) 895 def test_fetchone(self): 896 cur = self.con.cursor() 897 cur.execute('select * from country') 898 row = cur.fetchone() 899 self.assertTupleEqual(row, ('USA', 'Dollar')) 900 def test_fetchall(self): 901 cur = self.con.cursor() 902 cur.execute('select * from country') 903 rows = cur.fetchall() 904 if self.con.ods < fdb.ODS_FB_30: 905 self.assertListEqual(rows, 906 [('USA', 'Dollar'), ('England', 'Pound'), ('Canada', 'CdnDlr'), 907 ('Switzerland', 'SFranc'), ('Japan', 'Yen'), ('Italy', 'Lira'), 908 ('France', 'FFranc'), ('Germany', 'D-Mark'), ('Australia', 'ADollar'), 909 ('Hong Kong', 'HKDollar'), ('Netherlands', 'Guilder'), 910 ('Belgium', 'BFranc'), ('Austria', 'Schilling'), ('Fiji', 'FDollar')]) 911 else: 912 self.assertListEqual(rows, 913 [('USA', 'Dollar'), ('England', 'Pound'), ('Canada', 'CdnDlr'), 914 ('Switzerland', 'SFranc'), ('Japan', 'Yen'), ('Italy', 'Euro'), 915 ('France', 'Euro'), ('Germany', 'Euro'), ('Australia', 'ADollar'), 916 ('Hong Kong', 'HKDollar'), ('Netherlands', 'Euro'), 917 ('Belgium', 'Euro'), ('Austria', 'Euro'), ('Fiji', 'FDollar'), 918 ('Russia', 'Ruble'), ('Romania', 'RLeu')]) 919 def test_fetchmany(self): 920 cur = self.con.cursor() 921 cur.execute('select * from country') 922 rows = cur.fetchmany(10) 923 if self.con.ods < fdb.ODS_FB_30: 924 self.assertListEqual(rows, 925 [('USA', 'Dollar'), ('England', 'Pound'), ('Canada', 'CdnDlr'), 926 ('Switzerland', 'SFranc'), ('Japan', 'Yen'), ('Italy', 'Lira'), 927 ('France', 'FFranc'), ('Germany', 'D-Mark'), ('Australia', 'ADollar'), 928 ('Hong Kong', 'HKDollar')]) 929 rows = cur.fetchmany(10) 930 self.assertListEqual(rows, 931 [('Netherlands', 'Guilder'), ('Belgium', 'BFranc'), 932 ('Austria', 'Schilling'), ('Fiji', 'FDollar')]) 933 rows = cur.fetchmany(10) 934 self.assertEqual(len(rows), 0) 935 else: 936 self.assertListEqual(rows, 937 [('USA', 'Dollar'), ('England', 'Pound'), ('Canada', 'CdnDlr'), 938 ('Switzerland', 'SFranc'), ('Japan', 'Yen'), ('Italy', 'Euro'), 939 ('France', 'Euro'), ('Germany', 'Euro'), ('Australia', 'ADollar'), 940 ('Hong Kong', 'HKDollar')]) 941 rows = cur.fetchmany(10) 942 self.assertListEqual(rows, 943 [('Netherlands', 'Euro'), ('Belgium', 'Euro'), ('Austria', 'Euro'), 944 ('Fiji', 'FDollar'), ('Russia', 'Ruble'), ('Romania', 'RLeu')]) 945 rows = cur.fetchmany(10) 946 self.assertEqual(len(rows), 0) 947 def test_fetchonemap(self): 948 cur = self.con.cursor() 949 cur.execute('select * from country') 950 row = cur.fetchonemap() 951 self.assertListEqual(row.items(), [('COUNTRY', 'USA'), ('CURRENCY', 'Dollar')]) 952 def test_fetchallmap(self): 953 cur = self.con.cursor() 954 cur.execute('select * from country') 955 rows = cur.fetchallmap() 956 if self.con.ods < fdb.ODS_FB_30: 957 self.assertListEqual([row.items() for row in rows], 958 [[('COUNTRY', 'USA'), ('CURRENCY', 'Dollar')], 959 [('COUNTRY', 'England'), ('CURRENCY', 'Pound')], 960 [('COUNTRY', 'Canada'), ('CURRENCY', 'CdnDlr')], 961 [('COUNTRY', 'Switzerland'), ('CURRENCY', 'SFranc')], 962 [('COUNTRY', 'Japan'), ('CURRENCY', 'Yen')], 963 [('COUNTRY', 'Italy'), ('CURRENCY', 'Lira')], 964 [('COUNTRY', 'France'), ('CURRENCY', 'FFranc')], 965 [('COUNTRY', 'Germany'), ('CURRENCY', 'D-Mark')], 966 [('COUNTRY', 'Australia'), ('CURRENCY', 'ADollar')], 967 [('COUNTRY', 'Hong Kong'), ('CURRENCY', 'HKDollar')], 968 [('COUNTRY', 'Netherlands'), ('CURRENCY', 'Guilder')], 969 [('COUNTRY', 'Belgium'), ('CURRENCY', 'BFranc')], 970 [('COUNTRY', 'Austria'), ('CURRENCY', 'Schilling')], 971 [('COUNTRY', 'Fiji'), ('CURRENCY', 'FDollar')]]) 972 else: 973 self.assertListEqual([row.items() for row in rows], 974 [[('COUNTRY', 'USA'), ('CURRENCY', 'Dollar')], 975 [('COUNTRY', 'England'), ('CURRENCY', 'Pound')], 976 [('COUNTRY', 'Canada'), ('CURRENCY', 'CdnDlr')], 977 [('COUNTRY', 'Switzerland'), ('CURRENCY', 'SFranc')], 978 [('COUNTRY', 'Japan'), ('CURRENCY', 'Yen')], 979 [('COUNTRY', 'Italy'), ('CURRENCY', 'Euro')], 980 [('COUNTRY', 'France'), ('CURRENCY', 'Euro')], 981 [('COUNTRY', 'Germany'), ('CURRENCY', 'Euro')], 982 [('COUNTRY', 'Australia'), ('CURRENCY', 'ADollar')], 983 [('COUNTRY', 'Hong Kong'), ('CURRENCY', 'HKDollar')], 984 [('COUNTRY', 'Netherlands'), ('CURRENCY', 'Euro')], 985 [('COUNTRY', 'Belgium'), ('CURRENCY', 'Euro')], 986 [('COUNTRY', 'Austria'), ('CURRENCY', 'Euro')], 987 [('COUNTRY', 'Fiji'), ('CURRENCY', 'FDollar')], 988 [('COUNTRY', 'Russia'), ('CURRENCY', 'Ruble')], 989 [('COUNTRY', 'Romania'), ('CURRENCY', 'RLeu')]]) 990 def test_fetchmanymap(self): 991 cur = self.con.cursor() 992 cur.execute('select * from country') 993 rows = cur.fetchmanymap(10) 994 if self.con.ods < fdb.ODS_FB_30: 995 self.assertListEqual([row.items() for row in rows], 996 [[('COUNTRY', 'USA'), ('CURRENCY', 'Dollar')], 997 [('COUNTRY', 'England'), ('CURRENCY', 'Pound')], 998 [('COUNTRY', 'Canada'), ('CURRENCY', 'CdnDlr')], 999 [('COUNTRY', 'Switzerland'), ('CURRENCY', 'SFranc')], 1000 [('COUNTRY', 'Japan'), ('CURRENCY', 'Yen')], 1001 [('COUNTRY', 'Italy'), ('CURRENCY', 'Lira')], 1002 [('COUNTRY', 'France'), ('CURRENCY', 'FFranc')], 1003 [('COUNTRY', 'Germany'), ('CURRENCY', 'D-Mark')], 1004 [('COUNTRY', 'Australia'), ('CURRENCY', 'ADollar')], 1005 [('COUNTRY', 'Hong Kong'), ('CURRENCY', 'HKDollar')]]) 1006 rows = cur.fetchmanymap(10) 1007 self.assertListEqual([row.items() for row in rows], 1008 [[('COUNTRY', 'Netherlands'), ('CURRENCY', 'Guilder')], 1009 [('COUNTRY', 'Belgium'), ('CURRENCY', 'BFranc')], 1010 [('COUNTRY', 'Austria'), ('CURRENCY', 'Schilling')], 1011 [('COUNTRY', 'Fiji'), ('CURRENCY', 'FDollar')]]) 1012 rows = cur.fetchmany(10) 1013 self.assertEqual(len(rows), 0) 1014 else: 1015 self.assertListEqual([row.items() for row in rows], 1016 [[('COUNTRY', 'USA'), ('CURRENCY', 'Dollar')], 1017 [('COUNTRY', 'England'), ('CURRENCY', 'Pound')], 1018 [('COUNTRY', 'Canada'), ('CURRENCY', 'CdnDlr')], 1019 [('COUNTRY', 'Switzerland'), ('CURRENCY', 'SFranc')], 1020 [('COUNTRY', 'Japan'), ('CURRENCY', 'Yen')], 1021 [('COUNTRY', 'Italy'), ('CURRENCY', 'Euro')], 1022 [('COUNTRY', 'France'), ('CURRENCY', 'Euro')], 1023 [('COUNTRY', 'Germany'), ('CURRENCY', 'Euro')], 1024 [('COUNTRY', 'Australia'), ('CURRENCY', 'ADollar')], 1025 [('COUNTRY', 'Hong Kong'), ('CURRENCY', 'HKDollar')]]) 1026 rows = cur.fetchmanymap(10) 1027 self.assertListEqual([row.items() for row in rows], 1028 [[('COUNTRY', 'Netherlands'), ('CURRENCY', 'Euro')], 1029 [('COUNTRY', 'Belgium'), ('CURRENCY', 'Euro')], 1030 [('COUNTRY', 'Austria'), ('CURRENCY', 'Euro')], 1031 [('COUNTRY', 'Fiji'), ('CURRENCY', 'FDollar')], 1032 [('COUNTRY', 'Russia'), ('CURRENCY', 'Ruble')], 1033 [('COUNTRY', 'Romania'), ('CURRENCY', 'RLeu')]]) 1034 rows = cur.fetchmany(10) 1035 self.assertEqual(len(rows), 0) 1036 def test_rowcount(self): 1037 cur = self.con.cursor() 1038 self.assertEqual(cur.rowcount, -1) 1039 cur.execute('select * from project') 1040 self.assertEqual(cur.rowcount, 0) 1041 cur.fetchone() 1042 rcount = 1 if FBTEST_HOST == '' and self.con.engine_version >= 3.0 else 6 1043 self.assertEqual(cur.rowcount, rcount) 1044 def test_name(self): 1045 def assign_name(): 1046 cur.name = 'testx' 1047 cur = self.con.cursor() 1048 self.assertIsNone(cur.name) 1049 self.assertRaises(fdb.ProgrammingError, assign_name) 1050 cur.execute('select * from country') 1051 cur.name = 'test' 1052 self.assertEqual(cur.name, 'test') 1053 self.assertRaises(fdb.ProgrammingError, assign_name) 1054 def test_use_after_close(self): 1055 cmd = 'select * from country' 1056 cur = self.con.cursor() 1057 cur.execute(cmd) 1058 cur.close() 1059 cur.execute(cmd) 1060 row = cur.fetchone() 1061 self.assertTupleEqual(row, ('USA', 'Dollar')) 1062 1063class TestPreparedStatement(FDBTestBase): 1064 def setUp(self): 1065 super(TestPreparedStatement, self).setUp() 1066 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 1067 self.con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 1068 user=FBTEST_USER, password=FBTEST_PASSWORD) 1069 #self.con.execute_immediate("recreate table t (c1 integer)") 1070 #self.con.commit() 1071 def tearDown(self): 1072 self.con.execute_immediate("delete from t") 1073 self.con.commit() 1074 self.con.close() 1075 def test_basic(self): 1076 cur = self.con.cursor() 1077 ps = cur.prep('select * from country') 1078 self.assertEqual(ps._in_sqlda.sqln, 10) 1079 self.assertEqual(ps._in_sqlda.sqld, 0) 1080 self.assertEqual(ps._out_sqlda.sqln, 10) 1081 self.assertEqual(ps._out_sqlda.sqld, 2) 1082 self.assertEqual(ps.statement_type, 1) 1083 self.assertEqual(ps.sql, 'select * from country') 1084 def test_get_plan(self): 1085 cur = self.con.cursor() 1086 ps = cur.prep('select * from job') 1087 self.assertEqual(ps.plan, "PLAN (JOB NATURAL)") 1088 def test_execution(self): 1089 cur = self.con.cursor() 1090 ps = cur.prep('select * from country') 1091 cur.execute(ps) 1092 row = cur.fetchone() 1093 self.assertTupleEqual(row, ('USA', 'Dollar')) 1094 def test_wrong_cursor(self): 1095 cur = self.con.cursor() 1096 cur2 = self.con.cursor() 1097 ps = cur.prep('select * from country') 1098 with self.assertRaises(ValueError) as cm: 1099 cur2.execute(ps) 1100 self.assertTupleEqual(cm.exception.args, 1101 ('PreparedStatement was created by different Cursor.',)) 1102 1103 1104class TestArrays(FDBTestBase): 1105 def setUp(self): 1106 super(TestArrays, self).setUp() 1107 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 1108 self.con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 1109 user=FBTEST_USER, password=FBTEST_PASSWORD) 1110 tbl = """recreate table AR (c1 integer, 1111 c2 integer[1:4,0:3,1:2], 1112 c3 varchar(15)[0:5,1:2], 1113 c4 char(5)[5], 1114 c5 timestamp[2], 1115 c6 time[2], 1116 c7 decimal(10,2)[2], 1117 c8 numeric(10,2)[2], 1118 c9 smallint[2], 1119 c10 bigint[2], 1120 c11 float[2], 1121 c12 double precision[2], 1122 c13 decimal(10,1)[2], 1123 c14 decimal(10,5)[2], 1124 c15 decimal(18,5)[2] 1125 ) 1126""" 1127 # 1128 self.c2 = [[[1, 1], [2, 2], [3, 3], [4, 4]], [[5, 5], [6, 6], [7, 7], [8, 8]], [[9, 9], [10, 10], [11, 11], [12, 12]], [[13, 13], [14, 14], [15, 15], [16, 16]]] 1129 self.c3 = [['a', 'a'], ['bb', 'bb'], ['ccc', 'ccc'], ['dddd', 'dddd'], ['eeeee', 'eeeee'], ['fffffff78901234', 'fffffff78901234']] 1130 self.c4 = ['a ', 'bb ', 'ccc ', 'dddd ', 'eeeee'] 1131 self.c5 = [datetime.datetime(2012, 11, 22, 12, 8, 24, 474800), datetime.datetime(2012, 11, 22, 12, 8, 24, 474800)] 1132 self.c6 = [datetime.time(12, 8, 24, 474800), datetime.time(12, 8, 24, 474800)] 1133 self.c7 = [decimal.Decimal('10.22'), decimal.Decimal('100000.33')] 1134 self.c8 = [decimal.Decimal('10.22'), decimal.Decimal('100000.33')] 1135 self.c9 = [1, 0] 1136 self.c10 = [5555555, 7777777] 1137 self.c11 = [3.140000104904175, 3.140000104904175] 1138 self.c12 = [3.14, 3.14] 1139 self.c13 = [decimal.Decimal('10.2'), decimal.Decimal('100000.3')] 1140 self.c14 = [decimal.Decimal('10.22222'), decimal.Decimal('100000.333')] 1141 self.c15 = [decimal.Decimal('1000000000000.22222'), decimal.Decimal('1000000000000.333')] 1142 self.c16 = [True, False, True] 1143 #self.con.execute_immediate(tbl) 1144 #self.con.commit() 1145 #cur = self.con.cursor() 1146 #cur.execute("insert into ar (c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12) values (1,?,?,?,?,?,?,?,?,?,?,?)", 1147 #[self.c2,self.c3,self.c4,self.c5,self.c6,self.c7,self.c8,self.c9, 1148 #self.c10,self.c11,self.c12]) 1149 #cur.execute("insert into ar (c1,c2) values (2,?)",[self.c2]) 1150 #cur.execute("insert into ar (c1,c3) values (3,?)",[self.c3]) 1151 #cur.execute("insert into ar (c1,c4) values (4,?)",[self.c4]) 1152 #cur.execute("insert into ar (c1,c5) values (5,?)",[self.c5]) 1153 #cur.execute("insert into ar (c1,c6) values (6,?)",[self.c6]) 1154 #cur.execute("insert into ar (c1,c7) values (7,?)",[self.c7]) 1155 #cur.execute("insert into ar (c1,c8) values (8,?)",[self.c8]) 1156 #cur.execute("insert into ar (c1,c9) values (9,?)",[self.c9]) 1157 #cur.execute("insert into ar (c1,c10) values (10,?)",[self.c10]) 1158 #cur.execute("insert into ar (c1,c11) values (11,?)",[self.c11]) 1159 #cur.execute("insert into ar (c1,c12) values (12,?)",[self.c12]) 1160 #cur.execute("insert into ar (c1,c13) values (13,?)",[self.c13]) 1161 #cur.execute("insert into ar (c1,c14) values (14,?)",[self.c14]) 1162 #cur.execute("insert into ar (c1,c15) values (15,?)",[self.c15]) 1163 #self.con.commit() 1164 def tearDown(self): 1165 self.con.execute_immediate("delete from AR where c1>=100") 1166 self.con.commit() 1167 self.con.close() 1168 def test_basic(self): 1169 cur = self.con.cursor() 1170 cur.execute("select LANGUAGE_REQ from job "\ 1171 "where job_code='Eng' and job_grade=3 and job_country='Japan'") 1172 row = cur.fetchone() 1173 self.assertTupleEqual(row, 1174 (['Japanese\n', 'Mandarin\n', 'English\n', '\n', '\n'],)) 1175 cur.execute('select QUART_HEAD_CNT from proj_dept_budget') 1176 row = cur.fetchall() 1177 self.assertListEqual(row, 1178 [([1, 1, 1, 0],), ([3, 2, 1, 0],), ([0, 0, 0, 1],), ([2, 1, 0, 0],), 1179 ([1, 1, 0, 0],), ([1, 1, 0, 0],), ([1, 1, 1, 1],), ([2, 3, 2, 1],), 1180 ([1, 1, 2, 2],), ([1, 1, 1, 2],), ([1, 1, 1, 2],), ([4, 5, 6, 6],), 1181 ([2, 2, 0, 3],), ([1, 1, 2, 2],), ([7, 7, 4, 4],), ([2, 3, 3, 3],), 1182 ([4, 5, 6, 6],), ([1, 1, 1, 1],), ([4, 5, 5, 3],), ([4, 3, 2, 2],), 1183 ([2, 2, 2, 1],), ([1, 1, 2, 3],), ([3, 3, 1, 1],), ([1, 1, 0, 0],)]) 1184 def test_read_full(self): 1185 cur = self.con.cursor() 1186 cur.execute("select c1,c2 from ar where c1=2") 1187 row = cur.fetchone() 1188 self.assertListEqual(row[1], self.c2) 1189 cur.execute("select c1,c3 from ar where c1=3") 1190 row = cur.fetchone() 1191 self.assertListEqual(row[1], self.c3) 1192 cur.execute("select c1,c4 from ar where c1=4") 1193 row = cur.fetchone() 1194 self.assertListEqual(row[1], self.c4) 1195 cur.execute("select c1,c5 from ar where c1=5") 1196 row = cur.fetchone() 1197 self.assertListEqual(row[1], self.c5) 1198 cur.execute("select c1,c6 from ar where c1=6") 1199 row = cur.fetchone() 1200 self.assertListEqual(row[1], self.c6) 1201 cur.execute("select c1,c7 from ar where c1=7") 1202 row = cur.fetchone() 1203 self.assertListEqual(row[1], self.c7) 1204 cur.execute("select c1,c8 from ar where c1=8") 1205 row = cur.fetchone() 1206 self.assertListEqual(row[1], self.c8) 1207 cur.execute("select c1,c9 from ar where c1=9") 1208 row = cur.fetchone() 1209 self.assertListEqual(row[1], self.c9) 1210 cur.execute("select c1,c10 from ar where c1=10") 1211 row = cur.fetchone() 1212 self.assertListEqual(row[1], self.c10) 1213 cur.execute("select c1,c11 from ar where c1=11") 1214 row = cur.fetchone() 1215 self.assertListEqual(row[1], self.c11) 1216 cur.execute("select c1,c12 from ar where c1=12") 1217 row = cur.fetchone() 1218 self.assertListEqual(row[1], self.c12) 1219 cur.execute("select c1,c13 from ar where c1=13") 1220 row = cur.fetchone() 1221 self.assertListEqual(row[1], self.c13) 1222 cur.execute("select c1,c14 from ar where c1=14") 1223 row = cur.fetchone() 1224 self.assertListEqual(row[1], self.c14) 1225 cur.execute("select c1,c15 from ar where c1=15") 1226 row = cur.fetchone() 1227 self.assertListEqual(row[1], self.c15) 1228 def test_write_full(self): 1229 cur = self.con.cursor() 1230 # INTEGER 1231 cur.execute("insert into ar (c1,c2) values (102,?)", [self.c2]) 1232 self.con.commit() 1233 cur.execute("select c1,c2 from ar where c1=102") 1234 row = cur.fetchone() 1235 self.assertListEqual(row[1], self.c2) 1236 1237 # VARCHAR 1238 cur.execute("insert into ar (c1,c3) values (103,?)", [self.c3]) 1239 self.con.commit() 1240 cur.execute("select c1,c3 from ar where c1=103") 1241 row = cur.fetchone() 1242 self.assertListEqual(row[1], self.c3) 1243 1244 cur.execute("insert into ar (c1,c3) values (103,?)", [tuple(self.c3)]) 1245 self.con.commit() 1246 cur.execute("select c1,c3 from ar where c1=103") 1247 row = cur.fetchone() 1248 self.assertListEqual(row[1], self.c3) 1249 1250 # CHAR 1251 cur.execute("insert into ar (c1,c4) values (104,?)", [self.c4]) 1252 self.con.commit() 1253 cur.execute("select c1,c4 from ar where c1=104") 1254 row = cur.fetchone() 1255 self.assertListEqual(row[1], self.c4) 1256 1257 # TIMESTAMP 1258 cur.execute("insert into ar (c1,c5) values (105,?)", [self.c5]) 1259 self.con.commit() 1260 cur.execute("select c1,c5 from ar where c1=105") 1261 row = cur.fetchone() 1262 self.assertListEqual(row[1], self.c5) 1263 1264 # TIME OK 1265 cur.execute("insert into ar (c1,c6) values (106,?)", [self.c6]) 1266 self.con.commit() 1267 cur.execute("select c1,c6 from ar where c1=106") 1268 row = cur.fetchone() 1269 self.assertListEqual(row[1], self.c6) 1270 1271 # DECIMAL(10,2) 1272 cur.execute("insert into ar (c1,c7) values (107,?)", [self.c7]) 1273 self.con.commit() 1274 cur.execute("select c1,c7 from ar where c1=107") 1275 row = cur.fetchone() 1276 self.assertListEqual(row[1], self.c7) 1277 1278 # NUMERIC(10,2) 1279 cur.execute("insert into ar (c1,c8) values (108,?)", [self.c8]) 1280 self.con.commit() 1281 cur.execute("select c1,c8 from ar where c1=108") 1282 row = cur.fetchone() 1283 self.assertListEqual(row[1], self.c8) 1284 1285 # SMALLINT 1286 cur.execute("insert into ar (c1,c9) values (109,?)", [self.c9]) 1287 self.con.commit() 1288 cur.execute("select c1,c9 from ar where c1=109") 1289 row = cur.fetchone() 1290 self.assertListEqual(row[1], self.c9) 1291 1292 # BIGINT 1293 cur.execute("insert into ar (c1,c10) values (110,?)", [self.c10]) 1294 self.con.commit() 1295 cur.execute("select c1,c10 from ar where c1=110") 1296 row = cur.fetchone() 1297 self.assertListEqual(row[1], self.c10) 1298 1299 # FLOAT 1300 cur.execute("insert into ar (c1,c11) values (111,?)", [self.c11]) 1301 self.con.commit() 1302 cur.execute("select c1,c11 from ar where c1=111") 1303 row = cur.fetchone() 1304 self.assertListEqual(row[1], self.c11) 1305 1306 # DOUBLE PRECISION 1307 cur.execute("insert into ar (c1,c12) values (112,?)", [self.c12]) 1308 self.con.commit() 1309 cur.execute("select c1,c12 from ar where c1=112") 1310 row = cur.fetchone() 1311 self.assertListEqual(row[1], self.c12) 1312 1313 # DECIMAL(10,1) OK 1314 cur.execute("insert into ar (c1,c13) values (113,?)", [self.c13]) 1315 self.con.commit() 1316 cur.execute("select c1,c13 from ar where c1=113") 1317 row = cur.fetchone() 1318 self.assertListEqual(row[1], self.c13) 1319 1320 # DECIMAL(10,5) 1321 cur.execute("insert into ar (c1,c14) values (114,?)", [self.c14]) 1322 self.con.commit() 1323 cur.execute("select c1,c14 from ar where c1=114") 1324 row = cur.fetchone() 1325 self.assertListEqual(row[1], self.c14) 1326 1327 # DECIMAL(18,5) 1328 cur.execute("insert into ar (c1,c15) values (115,?)", [self.c15]) 1329 self.con.commit() 1330 cur.execute("select c1,c15 from ar where c1=115") 1331 row = cur.fetchone() 1332 self.assertListEqual(row[1], self.c15) 1333 1334 if self.version == FB30: 1335 # BOOLEAN 1336 cur.execute("insert into ar (c1,c16) values (116,?)", [self.c16]) 1337 self.con.commit() 1338 cur.execute("select c1,c16 from ar where c1=116") 1339 row = cur.fetchone() 1340 self.assertListEqual(row[1], self.c16) 1341 def test_write_wrong(self): 1342 cur = self.con.cursor() 1343 1344 with self.assertRaises(ValueError) as cm: 1345 cur.execute("insert into ar (c1,c2) values (102,?)", [self.c3]) 1346 self.assertTupleEqual(cm.exception.args, ('Incorrect ARRAY field value.',)) 1347 with self.assertRaises(ValueError) as cm: 1348 cur.execute("insert into ar (c1,c2) values (102,?)", [self.c2[:-1]]) 1349 self.assertTupleEqual(cm.exception.args, ('Incorrect ARRAY field value.',)) 1350 1351class TestInsertData(FDBTestBase): 1352 def setUp(self): 1353 super(TestInsertData, self).setUp() 1354 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 1355 self.con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 1356 user=FBTEST_USER, password=FBTEST_PASSWORD) 1357 self.con2 = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 1358 user=FBTEST_USER, password=FBTEST_PASSWORD, 1359 charset='utf-8') 1360 #self.con.execute_immediate("recreate table t (c1 integer)") 1361 #self.con.commit() 1362 #self.con.execute_immediate("RECREATE TABLE T2 (C1 Smallint,C2 Integer,C3 Bigint,C4 Char(5),C5 Varchar(10),C6 Date,C7 Time,C8 Timestamp,C9 Blob sub_type 1,C10 Numeric(18,2),C11 Decimal(18,2),C12 Float,C13 Double precision,C14 Numeric(8,4),C15 Decimal(8,4))") 1363 #self.con.commit() 1364 def tearDown(self): 1365 self.con2.close() 1366 self.con.execute_immediate("delete from t") 1367 self.con.execute_immediate("delete from t2") 1368 self.con.commit() 1369 self.con.close() 1370 def test_insert_integers(self): 1371 cur = self.con.cursor() 1372 cur.execute('insert into T2 (C1,C2,C3) values (?,?,?)', [1, 1, 1]) 1373 self.con.commit() 1374 cur.execute('select C1,C2,C3 from T2 where C1 = 1') 1375 rows = cur.fetchall() 1376 self.assertListEqual(rows, [(1, 1, 1)]) 1377 cur.execute('insert into T2 (C1,C2,C3) values (?,?,?)', 1378 [2, 1, 9223372036854775807]) 1379 cur.execute('insert into T2 (C1,C2,C3) values (?,?,?)', 1380 [2, 1, -9223372036854775807-1]) 1381 self.con.commit() 1382 cur.execute('select C1,C2,C3 from T2 where C1 = 2') 1383 rows = cur.fetchall() 1384 self.assertListEqual(rows, 1385 [(2, 1, 9223372036854775807), (2, 1, -9223372036854775808)]) 1386 def test_insert_char_varchar(self): 1387 cur = self.con.cursor() 1388 cur.execute('insert into T2 (C1,C4,C5) values (?,?,?)', [2, 'AA', 'AA']) 1389 self.con.commit() 1390 cur.execute('select C1,C4,C5 from T2 where C1 = 2') 1391 rows = cur.fetchall() 1392 self.assertListEqual(rows, [(2, 'AA ', 'AA')]) 1393 # Too long values 1394 with self.assertRaises(ValueError) as cm: 1395 cur.execute('insert into T2 (C1,C4) values (?,?)', [3, '123456']) 1396 self.con.commit() 1397 self.assertTupleEqual(cm.exception.args, 1398 ('Value of parameter (1) is too long, expected 5, found 6',)) 1399 with self.assertRaises(ValueError) as cm: 1400 cur.execute('insert into T2 (C1,C5) values (?,?)', [3, '12345678901']) 1401 self.con.commit() 1402 self.assertTupleEqual(cm.exception.args, 1403 ('Value of parameter (1) is too long, expected 10, found 11',)) 1404 def test_insert_datetime(self): 1405 cur = self.con.cursor() 1406 now = datetime.datetime(2011, 11, 13, 15, 00, 1, 200) 1407 cur.execute('insert into T2 (C1,C6,C7,C8) values (?,?,?,?)', [3, now.date(), now.time(), now]) 1408 self.con.commit() 1409 cur.execute('select C1,C6,C7,C8 from T2 where C1 = 3') 1410 rows = cur.fetchall() 1411 self.assertListEqual(rows, 1412 [(3, datetime.date(2011, 11, 13), datetime.time(15, 0, 1, 200), 1413 datetime.datetime(2011, 11, 13, 15, 0, 1, 200))]) 1414 1415 cur.execute('insert into T2 (C1,C6,C7,C8) values (?,?,?,?)', [4, '2011-11-13', '15:0:1:200', '2011-11-13 15:0:1:200']) 1416 self.con.commit() 1417 cur.execute('select C1,C6,C7,C8 from T2 where C1 = 4') 1418 rows = cur.fetchall() 1419 self.assertListEqual(rows, 1420 [(4, datetime.date(2011, 11, 13), datetime.time(15, 0, 1, 200000), 1421 datetime.datetime(2011, 11, 13, 15, 0, 1, 200000))]) 1422 def test_insert_blob(self): 1423 cur = self.con.cursor() 1424 cur2 = self.con2.cursor() 1425 cur.execute('insert into T2 (C1,C9) values (?,?)', [4, 'This is a BLOB!']) 1426 cur.transaction.commit() 1427 cur.execute('select C1,C9 from T2 where C1 = 4') 1428 rows = cur.fetchall() 1429 self.assertListEqual(rows, [(4, 'This is a BLOB!')]) 1430 # Non-textual BLOB 1431 blob_data = fdb.bs([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 1432 cur.execute('insert into T2 (C1,C16) values (?,?)', [8, blob_data]) 1433 cur.transaction.commit() 1434 cur.execute('select C1,C16 from T2 where C1 = 8') 1435 rows = cur.fetchall() 1436 self.assertListEqual(rows, [(8, blob_data)]) 1437 # BLOB bigger than max. segment size 1438 big_blob = '123456789' * 10000 1439 cur.execute('insert into T2 (C1,C9) values (?,?)', [5, big_blob]) 1440 cur.transaction.commit() 1441 cur.execute('select C1,C9 from T2 where C1 = 5') 1442 row = cur.fetchone() 1443 self.assertIsInstance(row[1], fdb.BlobReader) 1444 self.assertEqual(row[1].read(), big_blob) 1445 # Unicode in BLOB 1446 blob_text = 'This is a BLOB!' 1447 if not isinstance(blob_text, ibase.myunicode): 1448 blob_text = blob_text.decode('utf-8') 1449 cur2.execute('insert into T2 (C1,C9) values (?,?)', [6, blob_text]) 1450 cur2.transaction.commit() 1451 cur2.execute('select C1,C9 from T2 where C1 = 6') 1452 rows = cur2.fetchall() 1453 self.assertListEqual(rows, [(6, blob_text)]) 1454 # Unicode non-textual BLOB 1455 with self.assertRaises(TypeError) as cm: 1456 cur2.execute('insert into T2 (C1,C16) values (?,?)', [7, blob_text]) 1457 self.assertTupleEqual(cm.exception.args, 1458 ("Unicode strings are not acceptable input for a non-textual BLOB column.",)) 1459 def test_insert_float_double(self): 1460 cur = self.con.cursor() 1461 cur.execute('insert into T2 (C1,C12,C13) values (?,?,?)', [5, 1.0, 1.0]) 1462 self.con.commit() 1463 cur.execute('select C1,C12,C13 from T2 where C1 = 5') 1464 rows = cur.fetchall() 1465 self.assertListEqual(rows, [(5, 1.0, 1.0)]) 1466 cur.execute('insert into T2 (C1,C12,C13) values (?,?,?)', [6, 1, 1]) 1467 self.con.commit() 1468 cur.execute('select C1,C12,C13 from T2 where C1 = 6') 1469 rows = cur.fetchall() 1470 self.assertListEqual(rows, [(6, 1.0, 1.0)]) 1471 def test_insert_numeric_decimal(self): 1472 cur = self.con.cursor() 1473 cur.execute('insert into T2 (C1,C10,C11) values (?,?,?)', [6, 1.1, 1.1]) 1474 cur.execute('insert into T2 (C1,C10,C11) values (?,?,?)', [6, decimal.Decimal('100.11'), decimal.Decimal('100.11')]) 1475 self.con.commit() 1476 cur.execute('select C1,C10,C11 from T2 where C1 = 6') 1477 rows = cur.fetchall() 1478 self.assertListEqual(rows, 1479 [(6, Decimal('1.1'), Decimal('1.1')), 1480 (6, Decimal('100.11'), Decimal('100.11'))]) 1481 def test_insert_returning(self): 1482 cur = self.con.cursor() 1483 cur.execute('insert into T2 (C1,C10,C11) values (?,?,?) returning C1', [7, 1.1, 1.1]) 1484 result = cur.fetchall() 1485 self.assertListEqual(result, [(7,)]) 1486 def test_insert_boolean(self): 1487 if self.version == FB30: 1488 cur = self.con.cursor() 1489 cur.execute('insert into T2 (C1,C17) values (?,?) returning C1', [8, True]) 1490 cur.execute('insert into T2 (C1,C17) values (?,?) returning C1', [8, False]) 1491 cur.execute('select C1,C17 from T2 where C1 = 8') 1492 result = cur.fetchall() 1493 self.assertListEqual(result, [(8, True), (8, False)]) 1494 1495class TestStoredProc(FDBTestBase): 1496 def setUp(self): 1497 super(TestStoredProc, self).setUp() 1498 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 1499 self.con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 1500 user=FBTEST_USER, password=FBTEST_PASSWORD) 1501 def tearDown(self): 1502 self.con.close() 1503 def test_callproc(self): 1504 cur = self.con.cursor() 1505 result = cur.callproc('sub_tot_budget', ['100']) 1506 self.assertListEqual(result, ['100']) 1507 row = cur.fetchone() 1508 self.assertTupleEqual(row, (Decimal('3800000'), Decimal('760000'), 1509 Decimal('500000'), Decimal('1500000'))) 1510 result = cur.callproc('sub_tot_budget', [100]) 1511 self.assertListEqual(result, [100]) 1512 row = cur.fetchone() 1513 self.assertTupleEqual(row, (Decimal('3800000'), Decimal('760000'), 1514 Decimal('500000'), Decimal('1500000'))) 1515 1516class TestServices(FDBTestBase): 1517 def setUp(self): 1518 super(TestServices, self).setUp() 1519 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 1520 def test_attach(self): 1521 svc = fdb.services.connect(host=FBTEST_HOST, password=FBTEST_PASSWORD) 1522 svc.close() 1523 def test_query(self): 1524 svc = fdb.services.connect(host=FBTEST_HOST, password=FBTEST_PASSWORD) 1525 self.assertEqual(svc.get_service_manager_version(), 2) 1526 self.assertIn('Firebird', svc.get_server_version()) 1527 self.assertIn('Firebird', svc.get_architecture()) 1528 x = svc.get_home_directory() 1529 #self.assertEqual(x,'/opt/firebird/') 1530 if svc.engine_version < 3.0: 1531 self.assertIn('security2.fdb', svc.get_security_database_path()) 1532 else: 1533 self.assertIn('security3.fdb', svc.get_security_database_path()) 1534 x = svc.get_lock_file_directory() 1535 #self.assertEqual(x,'/tmp/firebird/') 1536 x = svc.get_server_capabilities() 1537 self.assertIsInstance(x, type(tuple())) 1538 x = svc.get_message_file_directory() 1539 #self.assertEqual(x,'/opt/firebird/') 1540 con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 1541 user=FBTEST_USER, password=FBTEST_PASSWORD) 1542 con2 = fdb.connect(host=FBTEST_HOST, database='employee', 1543 user=FBTEST_USER, password=FBTEST_PASSWORD) 1544 self.assertGreaterEqual(len(svc.get_attached_database_names()), 2, "Should work for Superserver, may fail with value 0 for Classic") 1545 self.assertIn(self.dbfile.upper(), 1546 [s.upper() for s in svc.get_attached_database_names()]) 1547 1548 #self.assertIn('/opt/firebird/examples/empbuild/employee.fdb',x) 1549 self.assertGreaterEqual(svc.get_connection_count(), 2) 1550 svc.close() 1551 def test_running(self): 1552 svc = fdb.services.connect(host=FBTEST_HOST, password=FBTEST_PASSWORD) 1553 self.assertFalse(svc.isrunning()) 1554 svc.get_log() 1555 #self.assertTrue(svc.isrunning()) 1556 self.assertTrue(svc.fetching) 1557 # fetch materialized 1558 log = svc.readlines() 1559 self.assertFalse(svc.isrunning()) 1560 svc.close() 1561 def test_wait(self): 1562 svc = fdb.services.connect(host=FBTEST_HOST, password=FBTEST_PASSWORD) 1563 self.assertFalse(svc.isrunning()) 1564 svc.get_log() 1565 self.assertTrue(svc.isrunning()) 1566 self.assertTrue(svc.fetching) 1567 svc.wait() 1568 self.assertFalse(svc.isrunning()) 1569 self.assertFalse(svc.fetching) 1570 svc.close() 1571 1572class TestServices2(FDBTestBase): 1573 def setUp(self): 1574 super(TestServices2, self).setUp() 1575 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 1576 self.fbk = os.path.join(self.dbpath, 'test_employee.fbk') 1577 self.fbk2 = os.path.join(self.dbpath, 'test_employee.fbk2') 1578 self.rfdb = os.path.join(self.dbpath, 'test_employee.fdb') 1579 self.svc = fdb.services.connect(host=FBTEST_HOST, password=FBTEST_PASSWORD) 1580 self.con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 1581 user=FBTEST_USER, password=FBTEST_PASSWORD) 1582 if not os.path.exists(self.rfdb): 1583 c = fdb.create_database(host=FBTEST_HOST, database=self.rfdb, 1584 user=FBTEST_USER, password=FBTEST_PASSWORD) 1585 c.close() 1586 def tearDown(self): 1587 self.svc.close() 1588 self.con.execute_immediate("delete from t") 1589 self.con.commit() 1590 self.con.close() 1591 if os.path.exists(self.rfdb): 1592 os.remove(self.rfdb) 1593 if os.path.exists(self.fbk): 1594 os.remove(self.fbk) 1595 if os.path.exists(self.fbk2): 1596 os.remove(self.fbk2) 1597 def test_log(self): 1598 def fetchline(line): 1599 output.append(line) 1600 self.svc.get_log() 1601 self.assertTrue(self.svc.fetching) 1602 # fetch materialized 1603 log = self.svc.readlines() 1604 self.assertFalse(self.svc.fetching) 1605 self.assertTrue(log) 1606 self.assertIsInstance(log, type(list())) 1607 # iterate over result 1608 self.svc.get_log() 1609 for line in self.svc: 1610 self.assertIsNotNone(line) 1611 self.assertIsInstance(line, fdb.StringType) 1612 self.assertFalse(self.svc.fetching) 1613 # callback 1614 output = [] 1615 self.svc.get_log(callback=fetchline) 1616 self.assertGreater(len(output), 0) 1617 self.assertEqual(output, log) 1618 def test_getLimboTransactionIDs(self): 1619 ids = self.svc.get_limbo_transaction_ids('employee') 1620 self.assertIsInstance(ids, type(list())) 1621 def test_getStatistics(self): 1622 def fetchline(line): 1623 output.append(line) 1624 self.svc.get_statistics('employee') 1625 self.assertTrue(self.svc.fetching) 1626 self.assertTrue(self.svc.isrunning()) 1627 # fetch materialized 1628 stats = self.svc.readlines() 1629 self.assertFalse(self.svc.fetching) 1630 self.assertFalse(self.svc.isrunning()) 1631 self.assertIsInstance(stats, type(list())) 1632 # iterate over result 1633 self.svc.get_statistics('employee', 1634 show_system_tables_and_indexes=True, 1635 show_record_versions=True) 1636 for line in self.svc: 1637 self.assertIsInstance(line, fdb.StringType) 1638 self.assertFalse(self.svc.fetching) 1639 # callback 1640 output = [] 1641 self.svc.get_statistics('employee', callback=fetchline) 1642 self.assertGreater(len(output), 0) 1643 # fetch only selected tables 1644 stats = self.svc.get_statistics('employee', 1645 show_user_data_pages=True, 1646 tables='COUNTRY') 1647 stats = '\n'.join(self.svc.readlines()) 1648 self.assertIn('COUNTRY', stats) 1649 self.assertNotIn('JOB', stats) 1650 # 1651 stats = self.svc.get_statistics('employee', 1652 show_user_data_pages=True, 1653 tables=('COUNTRY', 'PROJECT')) 1654 stats = '\n'.join(self.svc.readlines()) 1655 self.assertIn('COUNTRY', stats) 1656 self.assertIn('PROJECT', stats) 1657 self.assertNotIn('JOB', stats) 1658 def test_backup(self): 1659 def fetchline(line): 1660 output.append(line) 1661 self.svc.backup('employee', self.fbk) 1662 self.assertTrue(self.svc.fetching) 1663 self.assertTrue(self.svc.isrunning()) 1664 # fetch materialized 1665 report = self.svc.readlines() 1666 self.assertFalse(self.svc.fetching) 1667 self.assertFalse(self.svc.isrunning()) 1668 self.assertTrue(os.path.exists(self.fbk)) 1669 self.assertIsInstance(report, type(list())) 1670 # iterate over result 1671 self.svc.backup('employee', self.fbk, 1672 ignore_checksums=1, 1673 ignore_limbo_transactions=1, 1674 metadata_only=1, 1675 collect_garbage=0, 1676 transportable=0, 1677 convert_external_tables=1, 1678 compressed=0, 1679 no_db_triggers=0) 1680 for line in self.svc: 1681 self.assertIsNotNone(line) 1682 self.assertIsInstance(line, fdb.StringType) 1683 self.assertFalse(self.svc.fetching) 1684 # callback 1685 output = [] 1686 self.svc.backup('employee', self.fbk, callback=fetchline) 1687 self.assertGreater(len(output), 0) 1688 # Firebird 3.0 stats 1689 if self.con.ods >= fdb.ODS_FB_30: 1690 output = [] 1691 self.svc.backup('employee', self.fbk, callback=fetchline, 1692 stats=[fdb.services.STATS_TOTAL_TIME, fdb.services.STATS_TIME_DELTA, 1693 fdb.services.STATS_PAGE_READS, fdb.services.STATS_PAGE_WRITES]) 1694 self.assertGreater(len(output), 0) 1695 self.assertIn('gbak: time delta reads writes ', output) 1696 def test_restore(self): 1697 def fetchline(line): 1698 output.append(line) 1699 output = [] 1700 self.svc.backup('employee', self.fbk, callback=fetchline) 1701 self.assertTrue(os.path.exists(self.fbk)) 1702 self.svc.restore(self.fbk, self.rfdb, replace=1) 1703 self.assertTrue(self.svc.fetching) 1704 self.assertTrue(self.svc.isrunning()) 1705 # fetch materialized 1706 report = self.svc.readlines() 1707 self.assertFalse(self.svc.fetching) 1708 time.sleep(1) # Sometimes service is still running after there is no more data to fetch (slower shutdown) 1709 self.assertFalse(self.svc.isrunning()) 1710 self.assertIsInstance(report, type(list())) 1711 # iterate over result 1712 self.svc.restore(self.fbk, self.rfdb, replace=1) 1713 for line in self.svc: 1714 self.assertIsNotNone(line) 1715 self.assertIsInstance(line, fdb.StringType) 1716 self.assertFalse(self.svc.fetching) 1717 # callback 1718 output = [] 1719 self.svc.restore(self.fbk, self.rfdb, replace=1, callback=fetchline) 1720 self.assertGreater(len(output), 0) 1721 # Firebird 3.0 stats 1722 if self.con.ods >= fdb.ODS_FB_30: 1723 output = [] 1724 self.svc.restore(self.fbk, self.rfdb, replace=1, callback=fetchline, 1725 stats=[fdb.services.STATS_TOTAL_TIME, fdb.services.STATS_TIME_DELTA, 1726 fdb.services.STATS_PAGE_READS, fdb.services.STATS_PAGE_WRITES]) 1727 self.assertGreater(len(output), 0) 1728 self.assertIn('gbak: time delta reads writes ', output) 1729 def test_local_backup(self): 1730 self.svc.backup('employee', self.fbk) 1731 self.svc.wait() 1732 with open(self.fbk, mode='rb') as f: 1733 bkp = f.read() 1734 backup_stream = BytesIO() 1735 self.svc.local_backup('employee', backup_stream) 1736 backup_stream.seek(0) 1737 self.assertEqual(bkp, backup_stream.read()) 1738 def test_local_restore(self): 1739 backup_stream = BytesIO() 1740 self.svc.local_backup('employee', backup_stream) 1741 backup_stream.seek(0) 1742 self.svc.local_restore(backup_stream, self.rfdb, replace=1) 1743 self.assertTrue(os.path.exists(self.rfdb)) 1744 def test_nbackup(self): 1745 if self.con.engine_version < 2.5: 1746 return 1747 self.svc.nbackup('employee', self.fbk) 1748 self.assertTrue(os.path.exists(self.fbk)) 1749 def test_nrestore(self): 1750 if self.con.engine_version < 2.5: 1751 return 1752 self.test_nbackup() 1753 self.assertTrue(os.path.exists(self.fbk)) 1754 if os.path.exists(self.rfdb): 1755 os.remove(self.rfdb) 1756 self.svc.nrestore(self.fbk, self.rfdb) 1757 self.assertTrue(os.path.exists(self.rfdb)) 1758 def test_trace(self): 1759 if self.con.engine_version < 2.5: 1760 return 1761 trace_config = """<database %s> 1762 enabled true 1763 log_statement_finish true 1764 print_plan true 1765 include_filter %%SELECT%% 1766 exclude_filter %%RDB$%% 1767 time_threshold 0 1768 max_sql_length 2048 1769 </database> 1770 """ % self.dbfile 1771 svc2 = fdb.services.connect(host=FBTEST_HOST, password=FBTEST_PASSWORD) 1772 svcx = fdb.services.connect(host=FBTEST_HOST, password=FBTEST_PASSWORD) 1773 # Start trace sessions 1774 trace1_id = self.svc.trace_start(trace_config, 'test_trace_1') 1775 trace2_id = svc2.trace_start(trace_config) 1776 # check sessions 1777 sessions = svcx.trace_list() 1778 self.assertIn(trace1_id, sessions) 1779 seq = list(sessions[trace1_id].keys()) 1780 seq.sort() 1781 self.assertListEqual(seq,['date', 'flags', 'name', 'user']) 1782 self.assertIn(trace2_id, sessions) 1783 seq = list(sessions[trace2_id].keys()) 1784 seq.sort() 1785 self.assertListEqual(seq,['date', 'flags', 'user']) 1786 if self.con.engine_version < 3.0: 1787 self.assertListEqual(sessions[trace1_id]['flags'], ['active', ' admin', ' trace']) 1788 self.assertListEqual(sessions[trace2_id]['flags'], ['active', ' admin', ' trace']) 1789 else: 1790 self.assertListEqual(sessions[trace1_id]['flags'], ['active', ' trace']) 1791 self.assertListEqual(sessions[trace2_id]['flags'], ['active', ' trace']) 1792 # Pause session 1793 svcx.trace_suspend(trace2_id) 1794 self.assertIn('suspend', svcx.trace_list()[trace2_id]['flags']) 1795 # Resume session 1796 svcx.trace_resume(trace2_id) 1797 self.assertIn('active', svcx.trace_list()[trace2_id]['flags']) 1798 # Stop session 1799 svcx.trace_stop(trace2_id) 1800 self.assertNotIn(trace2_id, svcx.trace_list()) 1801 # Finalize 1802 svcx.trace_stop(trace1_id) 1803 svc2.close() 1804 svcx.close() 1805 def test_setDefaultPageBuffers(self): 1806 self.svc.set_default_page_buffers(self.rfdb, 100) 1807 def test_setSweepInterval(self): 1808 self.svc.set_sweep_interval(self.rfdb, 10000) 1809 def test_shutdown_bringOnline(self): 1810 if self.con.engine_version < 2.5: 1811 # Basic shutdown/online 1812 self.svc.shutdown(self.rfdb, 1813 fdb.services.SHUT_LEGACY, 1814 fdb.services.SHUT_FORCE, 0) 1815 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1816 self.assertIn('multi-user maintenance', ''.join(self.svc.readlines())) 1817 # Return to normal state 1818 self.svc.bring_online(self.rfdb, fdb.services.SHUT_LEGACY) 1819 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1820 self.assertNotIn('multi-user maintenance', ''.join(self.svc.readlines())) 1821 else: 1822 # Shutdown database to single-user maintenance mode 1823 self.svc.shutdown(self.rfdb, 1824 fdb.services.SHUT_SINGLE, 1825 fdb.services.SHUT_FORCE, 0) 1826 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1827 self.assertIn('single-user maintenance', ''.join(self.svc.readlines())) 1828 # Enable multi-user maintenance 1829 self.svc.bring_online(self.rfdb, fdb.services.SHUT_MULTI) 1830 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1831 self.assertIn('multi-user maintenance', ''.join(self.svc.readlines())) 1832 1833 # Go to full shutdown mode, disabling new attachments during 5 seconds 1834 self.svc.shutdown(self.rfdb, 1835 fdb.services.SHUT_FULL, 1836 fdb.services.SHUT_DENY_NEW_ATTACHMENTS, 5) 1837 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1838 self.assertIn('full shutdown', ''.join(self.svc.readlines())) 1839 # Enable single-user maintenance 1840 self.svc.bring_online(self.rfdb, fdb.services.SHUT_SINGLE) 1841 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1842 self.assertIn('single-user maintenance', ''.join(self.svc.readlines())) 1843 # Return to normal state 1844 self.svc.bring_online(self.rfdb) 1845 def test_setShouldReservePageSpace(self): 1846 self.svc.set_reserve_page_space(self.rfdb, False) 1847 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1848 self.assertIn('no reserve', ''.join(self.svc.readlines())) 1849 self.svc.set_reserve_page_space(self.rfdb, True) 1850 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1851 self.assertNotIn('no reserve', ''.join(self.svc.readlines())) 1852 def test_setWriteMode(self): 1853 # Forced writes 1854 self.svc.set_write_mode(self.rfdb, fdb.services.WRITE_FORCED) 1855 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1856 self.assertIn('force write', ''.join(self.svc.readlines())) 1857 # No Forced writes 1858 self.svc.set_write_mode(self.rfdb, fdb.services.WRITE_BUFFERED) 1859 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1860 self.assertNotIn('force write', ''.join(self.svc.readlines())) 1861 def test_setAccessMode(self): 1862 # Read Only 1863 self.svc.set_access_mode(self.rfdb, fdb.services.ACCESS_READ_ONLY) 1864 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1865 self.assertIn('read only', ''.join(self.svc.readlines())) 1866 # Read/Write 1867 self.svc.set_access_mode(self.rfdb, fdb.services.ACCESS_READ_WRITE) 1868 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1869 self.assertNotIn('read only', ''.join(self.svc.readlines())) 1870 def test_setSQLDialect(self): 1871 self.svc.set_sql_dialect(self.rfdb, 1) 1872 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1873 self.assertIn('Database dialect\t1', ''.join(self.svc.readlines())) 1874 self.svc.set_sql_dialect(self.rfdb, 3) 1875 self.svc.get_statistics(self.rfdb, show_only_db_header_pages=1) 1876 self.assertIn('Database dialect\t3', ''.join(self.svc.readlines())) 1877 def test_activateShadowFile(self): 1878 self.svc.activate_shadow(self.rfdb) 1879 def test_nolinger(self): 1880 if self.con.ods >= fdb.ODS_FB_30: 1881 self.svc.no_linger(self.rfdb) 1882 def test_sweep(self): 1883 self.svc.sweep(self.rfdb) 1884 def test_repair(self): 1885 result = self.svc.repair(self.rfdb) 1886 self.assertFalse(result) 1887 def test_validate(self): 1888 def fetchline(line): 1889 output.append(line) 1890 output = [] 1891 self.svc.validate(self.dbfile) 1892 # fetch materialized 1893 report = self.svc.readlines() 1894 self.assertFalse(self.svc.fetching) 1895 self.assertFalse(self.svc.isrunning()) 1896 self.assertIsInstance(report, type(list())) 1897 self.assertIn('Validation started', '/n'.join(report)) 1898 self.assertIn('Validation finished', '/n'.join(report)) 1899 # iterate over result 1900 self.svc.validate(self.dbfile) 1901 for line in self.svc: 1902 self.assertIsNotNone(line) 1903 self.assertIsInstance(line, fdb.StringType) 1904 self.assertFalse(self.svc.fetching) 1905 # callback 1906 output = [] 1907 self.svc.validate(self.dbfile, callback=fetchline) 1908 self.assertGreater(len(output), 0) 1909 # Parameters 1910 self.svc.validate(self.dbfile, include_tables='COUNTRY|SALES', 1911 include_indices='SALESTATX', lock_timeout=-1) 1912 report = '/n'.join(self.svc.readlines()) 1913 self.assertIn('(COUNTRY)', report) 1914 self.assertIn('(SALES)', report) 1915 self.assertIn('(SALESTATX)', report) 1916 def test_getUsers(self): 1917 users = self.svc.get_users() 1918 self.assertIsInstance(users, type(list())) 1919 self.assertIsInstance(users[0], fdb.services.User) 1920 self.assertEqual(users[0].name, 'SYSDBA') 1921 def test_manage_user(self): 1922 user = fdb.services.User('FDB_TEST') 1923 user.password = 'FDB_TEST' 1924 user.first_name = 'FDB' 1925 user.middle_name = 'X.' 1926 user.last_name = 'TEST' 1927 try: 1928 self.svc.remove_user(user) 1929 except fdb.DatabaseError as e: 1930 if 'SQLCODE: -85' in e.args[0]: 1931 pass 1932 else: 1933 raise e 1934 self.svc.add_user(user) 1935 self.assertTrue(self.svc.user_exists(user)) 1936 self.assertTrue(self.svc.user_exists('FDB_TEST')) 1937 users = [u for u in self.svc.get_users() if u.name == 'FDB_TEST'] 1938 self.assertTrue(users) 1939 self.assertEqual(len(users), 1) 1940 #self.assertEqual(users[0].password,'FDB_TEST') 1941 self.assertEqual(users[0].first_name, 'FDB') 1942 self.assertEqual(users[0].middle_name, 'X.') 1943 self.assertEqual(users[0].last_name, 'TEST') 1944 user.password = 'XFDB_TEST' 1945 user.first_name = 'XFDB' 1946 user.middle_name = 'XX.' 1947 user.last_name = 'XTEST' 1948 self.svc.modify_user(user) 1949 users = [u for u in self.svc.get_users() if u.name == 'FDB_TEST'] 1950 self.assertTrue(users) 1951 self.assertEqual(len(users), 1) 1952 #self.assertEqual(users[0].password,'XFDB_TEST') 1953 self.assertEqual(users[0].first_name, 'XFDB') 1954 self.assertEqual(users[0].middle_name, 'XX.') 1955 self.assertEqual(users[0].last_name, 'XTEST') 1956 self.svc.remove_user(user) 1957 self.assertFalse(self.svc.user_exists('FDB_TEST')) 1958 1959 1960class TestEvents(FDBTestBase): 1961 def setUp(self): 1962 super(TestEvents, self).setUp() 1963 self.dbfile = os.path.join(self.dbpath, 'fbevents.fdb') 1964 if os.path.exists(self.dbfile): 1965 os.remove(self.dbfile) 1966 self.con = fdb.create_database(host=FBTEST_HOST, database=self.dbfile, 1967 user=FBTEST_USER, password=FBTEST_PASSWORD) 1968 c = self.con.cursor() 1969 c.execute("CREATE TABLE T (PK Integer, C1 Integer)") 1970 c.execute("""CREATE TRIGGER EVENTS_AU FOR T ACTIVE 1971BEFORE UPDATE POSITION 0 1972AS 1973BEGIN 1974 if (old.C1 <> new.C1) then 1975 post_event 'c1_updated' ; 1976END""") 1977 c.execute("""CREATE TRIGGER EVENTS_AI FOR T ACTIVE 1978AFTER INSERT POSITION 0 1979AS 1980BEGIN 1981 if (new.c1 = 1) then 1982 post_event 'insert_1' ; 1983 else if (new.c1 = 2) then 1984 post_event 'insert_2' ; 1985 else if (new.c1 = 3) then 1986 post_event 'insert_3' ; 1987 else 1988 post_event 'insert_other' ; 1989END""") 1990 self.con.commit() 1991 def tearDown(self): 1992 self.con.drop_database() 1993 self.con.close() 1994 def test_one_event(self): 1995 def send_events(command_list): 1996 c = self.con.cursor() 1997 for cmd in command_list: 1998 c.execute(cmd) 1999 self.con.commit() 2000 2001 timed_event = threading.Timer(3.0, send_events, args=[["insert into T (PK,C1) values (1,1)",]]) 2002 with self.con.event_conduit(['insert_1']) as events: 2003 timed_event.start() 2004 e = events.wait() 2005 timed_event.join() 2006 self.assertDictEqual(e, {'insert_1': 1}) 2007 def test_multiple_events(self): 2008 def send_events(command_list): 2009 c = self.con.cursor() 2010 for cmd in command_list: 2011 c.execute(cmd) 2012 self.con.commit() 2013 cmds = ["insert into T (PK,C1) values (1,1)", 2014 "insert into T (PK,C1) values (1,2)", 2015 "insert into T (PK,C1) values (1,3)", 2016 "insert into T (PK,C1) values (1,1)", 2017 "insert into T (PK,C1) values (1,2)",] 2018 timed_event = threading.Timer(3.0, send_events, args=[cmds]) 2019 with self.con.event_conduit(['insert_1', 'insert_3']) as events: 2020 timed_event.start() 2021 e = events.wait() 2022 timed_event.join() 2023 self.assertDictEqual(e, {'insert_3': 1, 'insert_1': 2}) 2024 def test_20_events(self): 2025 def send_events(command_list): 2026 c = self.con.cursor() 2027 for cmd in command_list: 2028 c.execute(cmd) 2029 self.con.commit() 2030 cmds = ["insert into T (PK,C1) values (1,1)", 2031 "insert into T (PK,C1) values (1,2)", 2032 "insert into T (PK,C1) values (1,3)", 2033 "insert into T (PK,C1) values (1,1)", 2034 "insert into T (PK,C1) values (1,2)",] 2035 self.e = {} 2036 timed_event = threading.Timer(1.0, send_events, args=[cmds]) 2037 with self.con.event_conduit(['insert_1', 'A', 'B', 'C', 'D', 2038 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 2039 'N', 'O', 'P', 'Q', 'R', 'insert_3']) as events: 2040 timed_event.start() 2041 time.sleep(3) 2042 e = events.wait() 2043 timed_event.join() 2044 self.assertDictEqual(e, 2045 {'A': 0, 'C': 0, 'B': 0, 'E': 0, 'D': 0, 'G': 0, 'insert_1': 2, 2046 'I': 0, 'H': 0, 'K': 0, 'J': 0, 'M': 0, 'L': 0, 'O': 0, 'N': 0, 2047 'Q': 0, 'P': 0, 'R': 0, 'insert_3': 1, 'F': 0}) 2048 def test_flush_events(self): 2049 def send_events(command_list): 2050 c = self.con.cursor() 2051 for cmd in command_list: 2052 c.execute(cmd) 2053 self.con.commit() 2054 2055 timed_event = threading.Timer(3.0, send_events, args=[["insert into T (PK,C1) values (1,1)",]]) 2056 with self.con.event_conduit(['insert_1']) as events: 2057 send_events(["insert into T (PK,C1) values (1,1)", 2058 "insert into T (PK,C1) values (1,1)"]) 2059 time.sleep(2) 2060 events.flush() 2061 timed_event.start() 2062 e = events.wait() 2063 timed_event.join() 2064 self.assertDictEqual(e, {'insert_1': 1}) 2065 2066class TestStreamBLOBs(FDBTestBase): 2067 def setUp(self): 2068 super(TestStreamBLOBs, self).setUp() 2069 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 2070 self.con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 2071 user=FBTEST_USER, password=FBTEST_PASSWORD) 2072 #self.con.execute_immediate("recreate table t (c1 integer)") 2073 #self.con.commit() 2074 #self.con.execute_immediate("RECREATE TABLE T2 (C1 Smallint,C2 Integer,C3 Bigint,C4 Char(5),C5 Varchar(10),C6 Date,C7 Time,C8 Timestamp,C9 Blob sub_type 1,C10 Numeric(18,2),C11 Decimal(18,2),C12 Float,C13 Double precision,C14 Numeric(8,4),C15 Decimal(8,4))") 2075 #self.con.commit() 2076 def tearDown(self): 2077 self.con.execute_immediate("delete from t") 2078 self.con.execute_immediate("delete from t2") 2079 self.con.commit() 2080 self.con.close() 2081 def testBlobBasic(self): 2082 blob = """Firebird supports two types of blobs, stream and segmented. 2083The database stores segmented blobs in chunks. 2084Each chunk starts with a two byte length indicator followed by however many bytes of data were passed as a segment. 2085Stream blobs are stored as a continuous array of data bytes with no length indicators included.""" 2086 cur = self.con.cursor() 2087 cur.execute('insert into T2 (C1,C9) values (?,?)', [4, StringIO(blob)]) 2088 self.con.commit() 2089 p = cur.prep('select C1,C9 from T2 where C1 = 4') 2090 p.set_stream_blob('C9') 2091 cur.execute(p) 2092 row = cur.fetchone() 2093 blob_reader = row[1] 2094 ## Necessary to avoid bad BLOB handle on BlobReader.close in tearDown 2095 ## because BLOB handle is no longer valid after table purge 2096 with closing(p): 2097 self.assertEqual(blob_reader.read(20), 'Firebird supports tw') 2098 self.assertEqual(blob_reader.read(20), 'o types of blobs, st') 2099 self.assertEqual(blob_reader.read(400), 'ream and segmented.\nThe database stores segmented blobs in ' 2100 'chunks.\nEach chunk starts with a two byte length indicator ' 2101 'followed by however many bytes of data were passed as ' 2102 'a segment.\nStream blobs are stored as a continuous array ' 2103 'of data bytes with no length indicators included.') 2104 self.assertEqual(blob_reader.read(20), '') 2105 self.assertEqual(blob_reader.tell(), 318) 2106 blob_reader.seek(20) 2107 self.assertEqual(blob_reader.tell(), 20) 2108 self.assertEqual(blob_reader.read(20), 'o types of blobs, st') 2109 blob_reader.seek(0) 2110 self.assertEqual(blob_reader.tell(), 0) 2111 self.assertListEqual(blob_reader.readlines(), StringIO(blob).readlines()) 2112 blob_reader.seek(0) 2113 for line in blob_reader: 2114 self.assertIn(line.rstrip('\n'), blob.split('\n')) 2115 blob_reader.seek(0) 2116 self.assertEqual(blob_reader.read(), blob) 2117 blob_reader.seek(-9, os.SEEK_END) 2118 self.assertEqual(blob_reader.read(), 'included.') 2119 blob_reader.seek(-20, os.SEEK_END) 2120 blob_reader.seek(11, os.SEEK_CUR) 2121 self.assertEqual(blob_reader.read(), 'included.') 2122 blob_reader.seek(60) 2123 self.assertEqual(blob_reader.readline(), 2124 'The database stores segmented blobs in chunks.\n') 2125 self.assertIsInstance(blob_reader.blob_id, ibase.GDS_QUAD) 2126 self.assertTrue(blob_reader.is_text) 2127 self.assertEqual(blob_reader.blob_charset, None) 2128 self.assertEqual(blob_reader.charset, 'UTF-8') 2129 def testBlobExtended(self): 2130 blob = """Firebird supports two types of blobs, stream and segmented. 2131The database stores segmented blobs in chunks. 2132Each chunk starts with a two byte length indicator followed by however many bytes of data were passed as a segment. 2133Stream blobs are stored as a continuous array of data bytes with no length indicators included.""" 2134 cur = self.con.cursor() 2135 cur.execute('insert into T2 (C1,C9) values (?,?)', [1, StringIO(blob)]) 2136 cur.execute('insert into T2 (C1,C9) values (?,?)', [2, StringIO(blob)]) 2137 self.con.commit() 2138 p = cur.prep('select C1,C9 from T2') 2139 p.set_stream_blob('C9') 2140 cur.execute(p) 2141 #rows = [row for row in cur] 2142 # Necessary to avoid bad BLOB handle on BlobReader.close in tearDown 2143 # because BLOB handle is no longer valid after table purge 2144 with closing(p): 2145 for row in cur: 2146 blob_reader = row[1] 2147 self.assertEqual(blob_reader.read(20), 'Firebird supports tw') 2148 self.assertEqual(blob_reader.read(20), 'o types of blobs, st') 2149 self.assertEqual(blob_reader.read(400), 'ream and segmented.\nThe database stores segmented blobs ' 2150 'in chunks.\nEach chunk starts with a two byte length ' 2151 'indicator followed by however many bytes of data were ' 2152 'passed as a segment.\nStream blobs are stored as a ' 2153 'continuous array of data bytes with no length indicators ' 2154 'included.') 2155 self.assertEqual(blob_reader.read(20), '') 2156 self.assertEqual(blob_reader.tell(), 318) 2157 blob_reader.seek(20) 2158 self.assertEqual(blob_reader.tell(), 20) 2159 self.assertEqual(blob_reader.read(20), 'o types of blobs, st') 2160 blob_reader.seek(0) 2161 self.assertEqual(blob_reader.tell(), 0) 2162 self.assertListEqual(blob_reader.readlines(), 2163 StringIO(blob).readlines()) 2164 blob_reader.seek(0) 2165 for line in blob_reader: 2166 self.assertIn(line.rstrip('\n'), blob.split('\n')) 2167 blob_reader.seek(0) 2168 self.assertEqual(blob_reader.read(), blob) 2169 blob_reader.seek(-9, os.SEEK_END) 2170 self.assertEqual(blob_reader.read(), 'included.') 2171 blob_reader.seek(-20, os.SEEK_END) 2172 blob_reader.seek(11, os.SEEK_CUR) 2173 self.assertEqual(blob_reader.read(), 'included.') 2174 blob_reader.seek(60) 2175 self.assertEqual(blob_reader.readline(), 2176 'The database stores segmented blobs in chunks.\n') 2177 2178class TestCharsetConversion(FDBTestBase): 2179 def setUp(self): 2180 super(TestCharsetConversion, self).setUp() 2181 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 2182 self.con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 2183 user=FBTEST_USER, password=FBTEST_PASSWORD, 2184 charset='utf8') 2185 #self.con.execute_immediate("recreate table t (c1 integer)") 2186 #self.con.commit() 2187 #self.con.execute_immediate("RECREATE TABLE T2 (C1 Smallint,C2 Integer,C3 Bigint,C4 Char(5),C5 Varchar(10),C6 Date,C7 Time,C8 Timestamp,C9 Blob sub_type 1,C10 Numeric(18,2),C11 Decimal(18,2),C12 Float,C13 Double precision,C14 Numeric(8,4),C15 Decimal(8,4))") 2188 #self.con.commit() 2189 def tearDown(self): 2190 self.con.execute_immediate("delete from t3") 2191 self.con.execute_immediate("delete from t4") 2192 self.con.commit() 2193 self.con.close() 2194 def test_octets(self): 2195 bytestring = fdb.fbcore.bs([1, 2, 3, 4, 5]) 2196 cur = self.con.cursor() 2197 cur.execute("insert into T4 (C1, C_OCTETS, V_OCTETS) values (?,?,?)", 2198 (1, bytestring, bytestring)) 2199 self.con.commit() 2200 cur.execute("select C1, C_OCTETS, V_OCTETS from T4 where C1 = 1") 2201 row = cur.fetchone() 2202 if ibase.PYTHON_MAJOR_VER == 3: 2203 self.assertTupleEqual(row, 2204 (1, b'\x01\x02\x03\x04\x05', b'\x01\x02\x03\x04\x05')) 2205 else: 2206 self.assertTupleEqual(row, 2207 (1, '\x01\x02\x03\x04\x05', '\x01\x02\x03\x04\x05')) 2208 def test_utf82win1250(self): 2209 s5 = 'ěščřž' 2210 s30 = 'ěščřžýáíéúůďťňóĚŠČŘŽÝÁÍÉÚŮĎŤŇÓ' 2211 if ibase.PYTHON_MAJOR_VER != 3: 2212 s5 = s5.decode('utf8') 2213 s30 = s30.decode('utf8') 2214 2215 con1250 = fdb.connect(host=FBTEST_HOST, database=self.dbfile, user=FBTEST_USER, 2216 password=FBTEST_PASSWORD, charset='win1250') 2217 c_utf8 = self.con.cursor() 2218 c_win1250 = con1250.cursor() 2219 2220 # Insert unicode data 2221 c_utf8.execute("insert into T4 (C1, C_WIN1250, V_WIN1250, C_UTF8, V_UTF8)" 2222 "values (?,?,?,?,?)", 2223 (1, s5, s30, s5, s30)) 2224 self.con.commit() 2225 2226 # Should return the same unicode content when read from win1250 or utf8 connection 2227 c_win1250.execute("select C1, C_WIN1250, V_WIN1250," 2228 "C_UTF8, V_UTF8 from T4 where C1 = 1") 2229 row = c_win1250.fetchone() 2230 self.assertTupleEqual(row, (1, s5, s30, s5, s30)) 2231 c_utf8.execute("select C1, C_WIN1250, V_WIN1250," 2232 "C_UTF8, V_UTF8 from T4 where C1 = 1") 2233 row = c_utf8.fetchone() 2234 self.assertTupleEqual(row, (1, s5, s30, s5, s30)) 2235 2236 def testCharVarchar(self): 2237 s = 'Introdução' 2238 if ibase.PYTHON_MAJOR_VER != 3: 2239 s = s.decode('utf8') 2240 self.assertEqual(len(s), 10) 2241 data = tuple([1, s, s]) 2242 cur = self.con.cursor() 2243 cur.execute('insert into T3 (C1,C2,C3) values (?,?,?)', data) 2244 self.con.commit() 2245 cur.execute('select C1,C2,C3 from T3 where C1 = 1') 2246 row = cur.fetchone() 2247 self.assertEqual(row, data) 2248 def testBlob(self): 2249 s = """Introdução 2250 2251Este artigo descreve como você pode fazer o InterBase e o Firebird 1.5 2252coehabitarem pacificamente seu computador Windows. Por favor, note que esta 2253solução não permitirá que o Interbase e o Firebird rodem ao mesmo tempo. 2254Porém você poderá trocar entre ambos com um mínimo de luta. """ 2255 if ibase.PYTHON_MAJOR_VER != 3: 2256 s = s.decode('utf8') 2257 self.assertEqual(len(s), 292) 2258 data = tuple([2, s]) 2259 b_data = tuple([3, ibase.b('bytestring')]) 2260 cur = self.con.cursor() 2261 # Text BLOB 2262 cur.execute('insert into T3 (C1,C4) values (?,?)', data) 2263 self.con.commit() 2264 cur.execute('select C1,C4 from T3 where C1 = 2') 2265 row = cur.fetchone() 2266 self.assertEqual(row, data) 2267 # Insert Unicode into non-textual BLOB 2268 with self.assertRaises(TypeError) as cm: 2269 cur.execute('insert into T3 (C1,C5) values (?,?)', data) 2270 self.con.commit() 2271 self.assertTupleEqual(cm.exception.args, 2272 ('Unicode strings are not acceptable input for a non-textual BLOB column.',)) 2273 # Read binary from non-textual BLOB 2274 cur.execute('insert into T3 (C1,C5) values (?,?)', b_data) 2275 self.con.commit() 2276 cur.execute('select C1,C5 from T3 where C1 = 3') 2277 row = cur.fetchone() 2278 self.assertEqual(row, b_data) 2279 2280class TestSchema(FDBTestBase): 2281 def setUp(self): 2282 super(TestSchema, self).setUp() 2283 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 2284 #self.dbfile = '/home/data/db/employee30.fdb' 2285 self.con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 2286 user=FBTEST_USER, password=FBTEST_PASSWORD) 2287 def tearDown(self): 2288 self.con.close() 2289 def testSchemaBindClose(self): 2290 s = sm.Schema() 2291 self.assertTrue(s.closed) 2292 s.bind(self.con) 2293 # properties 2294 self.assertIsNone(s.description) 2295 self.assertIsNone(s.linger) 2296 self.assertEqual(s.owner_name, 'SYSDBA') 2297 self.assertEqual(s.default_character_set.name, 'NONE') 2298 if self.con.ods < fdb.ODS_FB_30: 2299 self.assertIsNone(s.security_class) 2300 else: 2301 self.assertEqual(s.security_class, 'SQL$363') 2302 self.assertFalse(s.closed) 2303 # 2304 s.close() 2305 self.assertTrue(s.closed) 2306 s.bind(self.con) 2307 self.assertFalse(s.closed) 2308 # 2309 s.bind(self.con) 2310 self.assertFalse(s.closed) 2311 # 2312 del s 2313 def testSchemaFromConnection(self): 2314 s = self.con.schema 2315 # enum_* disctionaries 2316 self.assertDictEqual(s.enum_param_type_from, 2317 {0: 'DATATYPE', 1: 'DOMAIN', 2: 'TYPE OF DOMAIN', 3: 'TYPE OF COLUMN'}) 2318 if self.con.ods <= fdb.ODS_FB_20: 2319 self.assertDictEqual(s.enum_object_types, 2320 {0: 'RELATION', 1: 'VIEW', 2: 'TRIGGER', 3: 'COMPUTED_FIELD', 2321 4: 'VALIDATION', 5: 'PROCEDURE', 6: 'EXPRESSION_INDEX', 2322 7: 'EXCEPTION', 8: 'USER', 9: 'FIELD', 10: 'INDEX', 2323 11: 'DEPENDENT_COUNT', 12: 'USER_GROUP', 13: 'ROLE', 2324 14: 'GENERATOR', 15: 'UDF', 16: 'BLOB_FILTER'}) 2325 self.assertDictEqual(s.enum_object_type_codes, 2326 {'INDEX': 10, 'EXCEPTION': 7, 'GENERATOR': 14, 'UDF': 15, 2327 'EXPRESSION_INDEX': 6, 'FIELD': 9, 'COMPUTED_FIELD': 3, 2328 'TRIGGER': 2, 'RELATION': 0, 'USER': 8, 'DEPENDENT_COUNT': 11, 2329 'USER_GROUP': 12, 'BLOB_FILTER': 16, 'ROLE': 13, 2330 'VALIDATION': 4, 'PROCEDURE': 5, 'VIEW': 1}) 2331 elif self.con.ods > fdb.ODS_FB_20 and self.con.ods < fdb.ODS_FB_30: 2332 self.assertDictEqual(s.enum_object_types, 2333 {0: 'RELATION', 1: 'VIEW', 2: 'TRIGGER', 3: 'COMPUTED_FIELD', 2334 4: 'VALIDATION', 5: 'PROCEDURE', 6: 'EXPRESSION_INDEX', 2335 7: 'EXCEPTION', 8: 'USER', 9: 'FIELD', 10: 'INDEX', 2336 12: 'USER_GROUP', 13: 'ROLE', 14: 'GENERATOR', 15: 'UDF', 2337 16: 'BLOB_FILTER', 17: 'COLLATION'}) 2338 self.assertDictEqual(s.enum_object_type_codes, 2339 {'INDEX': 10, 'EXCEPTION': 7, 'GENERATOR': 14, 'COLLATION': 17, 2340 'UDF': 15, 'EXPRESSION_INDEX': 6, 'FIELD': 9, 2341 'COMPUTED_FIELD': 3, 'TRIGGER': 2, 'RELATION': 0, 'USER': 8, 2342 'USER_GROUP': 12, 'BLOB_FILTER': 16, 'ROLE': 13, 2343 'VALIDATION': 4, 'PROCEDURE': 5, 'VIEW': 1}) 2344 else: 2345 self.assertDictEqual(s.enum_object_types, 2346 {0: 'RELATION', 1: 'VIEW', 2: 'TRIGGER', 3: 'COMPUTED_FIELD', 2347 4: 'VALIDATION', 5: 'PROCEDURE', 6: 'EXPRESSION_INDEX', 2348 7: 'EXCEPTION', 8: 'USER', 9: 'FIELD', 10: 'INDEX', 2349 11: 'CHARACTER_SET', 12: 'USER_GROUP', 13: 'ROLE', 2350 14: 'GENERATOR', 15: 'UDF', 16: 'BLOB_FILTER', 17: 'COLLATION', 2351 18:'PACKAGE', 19:'PACKAGE BODY'}) 2352 self.assertDictEqual(s.enum_object_type_codes, 2353 {'INDEX': 10, 'EXCEPTION': 7, 'GENERATOR': 14, 'COLLATION': 17, 2354 'UDF': 15, 'EXPRESSION_INDEX': 6, 'FIELD': 9, 2355 'COMPUTED_FIELD': 3, 'TRIGGER': 2, 'RELATION': 0, 'USER': 8, 2356 'USER_GROUP': 12, 'BLOB_FILTER': 16, 'ROLE': 13, 2357 'VALIDATION': 4, 'PROCEDURE': 5, 'VIEW': 1, 'CHARACTER_SET':11, 2358 'PACKAGE':18, 'PACKAGE BODY':19}) 2359 if self.con.ods <= fdb.ODS_FB_20: 2360 self.assertDictEqual(s.enum_character_set_names, 2361 {0: 'NONE', 1: 'BINARY', 2: 'ASCII7', 3: 'SQL_TEXT', 4: 'UTF-8', 2362 5: 'SJIS', 6: 'EUCJ', 9: 'DOS_737', 10: 'DOS_437', 2363 11: 'DOS_850', 12: 'DOS_865', 13: 'DOS_860', 14: 'DOS_863', 2364 15: 'DOS_775', 16: 'DOS_858', 17: 'DOS_862', 18: 'DOS_864', 2365 19: 'NEXT', 21: 'ANSI', 22: 'ISO-8859-2', 23: 'ISO-8859-3', 2366 34: 'ISO-8859-4', 35: 'ISO-8859-5', 36: 'ISO-8859-6', 2367 37: 'ISO-8859-7', 38: 'ISO-8859-8', 39: 'ISO-8859-9', 2368 40: 'ISO-8859-13', 44: 'WIN_949', 45: 'DOS_852', 46: 'DOS_857', 2369 47: 'DOS_861', 48: 'DOS_866', 49: 'DOS_869', 50: 'CYRL', 2370 51: 'WIN_1250', 52: 'WIN_1251', 53: 'WIN_1252', 54: 'WIN_1253', 2371 55: 'WIN_1254', 56: 'WIN_950', 57: 'WIN_936', 58: 'WIN_1255', 2372 59: 'WIN_1256', 60: 'WIN_1257', 63: 'KOI8R', 64: 'KOI8U', 2373 65: 'WIN1258'}) 2374 elif self.con.ods == fdb.ODS_FB_21: 2375 self.assertDictEqual(s.enum_character_set_names, 2376 {0: 'NONE', 1: 'BINARY', 2: 'ASCII7', 3: 'SQL_TEXT', 2377 4: 'UTF-8', 5: 'SJIS', 6: 'EUCJ', 9: 'DOS_737', 10: 'DOS_437', 2378 11: 'DOS_850', 12: 'DOS_865', 13: 'DOS_860', 14: 'DOS_863', 2379 15: 'DOS_775', 16: 'DOS_858', 17: 'DOS_862', 18: 'DOS_864', 2380 19: 'NEXT', 21: 'ANSI', 22: 'ISO-8859-2', 23: 'ISO-8859-3', 2381 34: 'ISO-8859-4', 35: 'ISO-8859-5', 36: 'ISO-8859-6', 2382 37: 'ISO-8859-7', 38: 'ISO-8859-8', 39: 'ISO-8859-9', 2383 40: 'ISO-8859-13', 44: 'WIN_949', 45: 'DOS_852', 46: 'DOS_857', 2384 47: 'DOS_861', 48: 'DOS_866', 49: 'DOS_869', 50: 'CYRL', 2385 51: 'WIN_1250', 52: 'WIN_1251', 53: 'WIN_1252', 54: 'WIN_1253', 2386 55: 'WIN_1254', 56: 'WIN_950', 57: 'WIN_936', 58: 'WIN_1255', 2387 59: 'WIN_1256', 60: 'WIN_1257', 63: 'KOI8R', 64: 'KOI8U', 2388 65: 'WIN1258', 66: 'TIS620', 67: 'GBK', 68: 'CP943C'}) 2389 elif self.con.ods >= fdb.ODS_FB_25: 2390 self.assertDictEqual(s.enum_character_set_names, 2391 {0: 'NONE', 1: 'BINARY', 2: 'ASCII7', 3: 'SQL_TEXT', 4: 'UTF-8', 2392 5: 'SJIS', 6: 'EUCJ', 9: 'DOS_737', 10: 'DOS_437', 11: 'DOS_850', 2393 12: 'DOS_865', 13: 'DOS_860', 14: 'DOS_863', 15: 'DOS_775', 2394 16: 'DOS_858', 17: 'DOS_862', 18: 'DOS_864', 19: 'NEXT', 2395 21: 'ANSI', 22: 'ISO-8859-2', 23: 'ISO-8859-3', 34: 'ISO-8859-4', 2396 35: 'ISO-8859-5', 36: 'ISO-8859-6', 37: 'ISO-8859-7', 2397 38: 'ISO-8859-8', 39: 'ISO-8859-9', 40: 'ISO-8859-13', 2398 44: 'WIN_949', 45: 'DOS_852', 46: 'DOS_857', 47: 'DOS_861', 2399 48: 'DOS_866', 49: 'DOS_869', 50: 'CYRL', 51: 'WIN_1250', 2400 52: 'WIN_1251', 53: 'WIN_1252', 54: 'WIN_1253', 55: 'WIN_1254', 2401 56: 'WIN_950', 57: 'WIN_936', 58: 'WIN_1255', 59: 'WIN_1256', 2402 60: 'WIN_1257', 63: 'KOI8R', 64: 'KOI8U', 65: 'WIN_1258', 2403 66: 'TIS620', 67: 'GBK', 68: 'CP943C', 69: 'GB18030'}) 2404 if self.con.ods < fdb.ODS_FB_30: 2405 self.assertDictEqual(s.enum_field_types, 2406 {35: 'TIMESTAMP', 37: 'VARYING', 7: 'SHORT', 8: 'LONG', 2407 9: 'QUAD', 10: 'FLOAT', 12: 'DATE', 45: 'BLOB_ID', 14: 'TEXT', 2408 13: 'TIME', 16: 'INT64', 40: 'CSTRING', 27: 'DOUBLE', 2409 261: 'BLOB'}) 2410 else: 2411 self.assertDictEqual(s.enum_field_types, 2412 {35: 'TIMESTAMP', 37: 'VARYING', 7: 'SHORT', 8: 'LONG', 2413 9: 'QUAD', 10: 'FLOAT', 12: 'DATE', 45: 'BLOB_ID', 14: 'TEXT', 2414 13: 'TIME', 16: 'INT64', 40: 'CSTRING', 27: 'DOUBLE', 2415 261: 'BLOB', 23:'BOOLEAN'}) 2416 if self.con.ods <= fdb.ODS_FB_20: 2417 self.assertDictEqual(s.enum_field_subtypes, 2418 {0: 'BINARY', 1: 'TEXT', 2: 'BLR', 3: 'ACL', 4: 'RANGES', 2419 5: 'SUMMARY', 6: 'FORMAT', 7: 'TRANSACTION_DESCRIPTION', 2420 8: 'EXTERNAL_FILE_DESCRIPTION'}) 2421 elif self.con.ods > fdb.ODS_FB_20: 2422 self.assertDictEqual(s.enum_field_subtypes, 2423 {0: 'BINARY', 1: 'TEXT', 2: 'BLR', 3: 'ACL', 4: 'RANGES', 2424 5: 'SUMMARY', 6: 'FORMAT', 7: 'TRANSACTION_DESCRIPTION', 2425 8: 'EXTERNAL_FILE_DESCRIPTION', 9: 'DEBUG_INFORMATION'}) 2426 self.assertDictEqual(s.enum_function_types, {0: 'VALUE', 1: 'BOOLEAN'}) 2427 self.assertDictEqual(s.enum_mechanism_types, 2428 {0: 'BY_VALUE', 1: 'BY_REFERENCE', 2429 2: 'BY_VMS_DESCRIPTOR', 3: 'BY_ISC_DESCRIPTOR', 2430 4: 'BY_SCALAR_ARRAY_DESCRIPTOR', 2431 5: 'BY_REFERENCE_WITH_NULL'}) 2432 if self.con.ods <= fdb.ODS_FB_20: 2433 self.assertDictEqual(s.enum_parameter_mechanism_types, {}) 2434 elif self.con.ods > fdb.ODS_FB_20: 2435 self.assertDictEqual(s.enum_parameter_mechanism_types, 2436 {0: 'NORMAL', 1: 'TYPE OF'}) 2437 self.assertDictEqual(s.enum_procedure_types, 2438 {0: 'LEGACY', 1: 'SELECTABLE', 2: 'EXECUTABLE'}) 2439 if self.con.ods <= fdb.ODS_FB_20: 2440 self.assertDictEqual(s.enum_relation_types, {}) 2441 elif self.con.ods > fdb.ODS_FB_20: 2442 self.assertDictEqual(s.enum_relation_types, 2443 {0: 'PERSISTENT', 1: 'VIEW', 2: 'EXTERNAL', 3: 'VIRTUAL', 2444 4: 'GLOBAL_TEMPORARY_PRESERVE', 5: 'GLOBAL_TEMPORARY_DELETE'}) 2445 if self.con.ods < fdb.ODS_FB_30: 2446 self.assertDictEqual(s.enum_system_flag_types, 2447 {0: 'USER', 1: 'SYSTEM', 2: 'QLI', 3: 'CHECK_CONSTRAINT', 2448 4: 'REFERENTIAL_CONSTRAINT', 5: 'VIEW_CHECK'}) 2449 else: 2450 self.assertDictEqual(s.enum_system_flag_types, 2451 {0: 'USER', 1: 'SYSTEM', 2: 'QLI', 3: 'CHECK_CONSTRAINT', 2452 4: 'REFERENTIAL_CONSTRAINT', 5: 'VIEW_CHECK', 6: 'IDENTITY_GENERATOR'}) 2453 self.assertDictEqual(s.enum_transaction_state_types, 2454 {1: 'LIMBO', 2: 'COMMITTED', 3: 'ROLLED_BACK'}) 2455 if self.con.ods <= fdb.ODS_FB_20: 2456 self.assertDictEqual(s.enum_trigger_types, 2457 {1: 'PRE_STORE', 2: 'POST_STORE', 3: 'PRE_MODIFY', 2458 4: 'POST_MODIFY', 5: 'PRE_ERASE', 6: 'POST_ERASE'}) 2459 elif self.con.ods > fdb.ODS_FB_20: 2460 self.assertDictEqual(s.enum_trigger_types, 2461 {8192: 'CONNECT', 1: 'PRE_STORE', 2: 'POST_STORE', 2462 3: 'PRE_MODIFY', 4: 'POST_MODIFY', 5: 'PRE_ERASE', 2463 6: 'POST_ERASE', 8193: 'DISCONNECT', 8194: 'TRANSACTION_START', 2464 8195: 'TRANSACTION_COMMIT', 8196: 'TRANSACTION_ROLLBACK'}) 2465 if self.con.ods >= fdb.ODS_FB_30: 2466 self.assertDictEqual(s.enum_parameter_types, 2467 {0: 'INPUT', 1: 'OUTPUT'}) 2468 self.assertDictEqual(s.enum_index_activity_flags, 2469 {0: 'ACTIVE', 1: 'INACTIVE'}) 2470 self.assertDictEqual(s.enum_index_unique_flags, 2471 {0: 'NON_UNIQUE', 1: 'UNIQUE'}) 2472 self.assertDictEqual(s.enum_trigger_activity_flags, 2473 {0: 'ACTIVE', 1: 'INACTIVE'}) 2474 self.assertDictEqual(s.enum_grant_options, 2475 {0: 'NONE', 1: 'GRANT_OPTION', 2: 'ADMIN_OPTION'}) 2476 self.assertDictEqual(s.enum_page_types, 2477 {1: 'HEADER', 2: 'PAGE_INVENTORY', 3: 'TRANSACTION_INVENTORY', 2478 4: 'POINTER', 5: 'DATA', 6: 'INDEX_ROOT', 7: 'INDEX_BUCKET', 2479 8: 'BLOB', 9: 'GENERATOR', 10: 'SCN_INVENTORY'}) 2480 self.assertDictEqual(s.enum_privacy_flags, 2481 {0: 'PUBLIC', 1: 'PRIVATE'}) 2482 self.assertDictEqual(s.enum_legacy_flags, 2483 {0: 'NEW_STYLE', 1: 'LEGACY_STYLE'}) 2484 self.assertDictEqual(s.enum_determinism_flags, 2485 {0: 'NON_DETERMINISTIC', 1: 'DETERMINISTIC'}) 2486 2487 # properties 2488 self.assertIsNone(s.description) 2489 self.assertEqual(s.owner_name, 'SYSDBA') 2490 self.assertEqual(s.default_character_set.name, 'NONE') 2491 if self.con.ods < fdb.ODS_FB_30: 2492 self.assertIsNone(s.security_class) 2493 else: 2494 self.assertEqual(s.security_class, 'SQL$363') 2495 # Lists of db objects 2496 self.assertIsInstance(s.collations, list) 2497 self.assertIsInstance(s.character_sets, list) 2498 self.assertIsInstance(s.exceptions, list) 2499 self.assertIsInstance(s.generators, list) 2500 self.assertIsInstance(s.sysgenerators, list) 2501 self.assertIsInstance(s.sequences, list) 2502 self.assertIsInstance(s.syssequences, list) 2503 self.assertIsInstance(s.domains, list) 2504 self.assertIsInstance(s.sysdomains, list) 2505 self.assertIsInstance(s.indices, list) 2506 self.assertIsInstance(s.sysindices, list) 2507 self.assertIsInstance(s.tables, list) 2508 self.assertIsInstance(s.systables, list) 2509 self.assertIsInstance(s.views, list) 2510 self.assertIsInstance(s.sysviews, list) 2511 self.assertIsInstance(s.triggers, list) 2512 self.assertIsInstance(s.systriggers, list) 2513 self.assertIsInstance(s.procedures, list) 2514 self.assertIsInstance(s.sysprocedures, list) 2515 self.assertIsInstance(s.constraints, list) 2516 self.assertIsInstance(s.roles, list) 2517 self.assertIsInstance(s.dependencies, list) 2518 self.assertIsInstance(s.functions, list) 2519 self.assertIsInstance(s.files, list) 2520 s.reload() 2521 if self.con.ods <= fdb.ODS_FB_20: 2522 self.assertEqual(len(s.collations), 138) 2523 elif self.con.ods == fdb.ODS_FB_21: 2524 self.assertEqual(len(s.collations), 146) 2525 elif self.con.ods == fdb.ODS_FB_25: 2526 self.assertEqual(len(s.collations), 149) 2527 elif self.con.ods >= fdb.ODS_FB_30: 2528 self.assertEqual(len(s.collations), 150) 2529 if self.con.ods <= fdb.ODS_FB_20: 2530 self.assertEqual(len(s.character_sets), 48) 2531 elif self.con.ods == fdb.ODS_FB_21: 2532 self.assertEqual(len(s.character_sets), 51) 2533 elif self.con.ods >= fdb.ODS_FB_25: 2534 self.assertEqual(len(s.character_sets), 52) 2535 self.assertEqual(len(s.exceptions), 5) 2536 self.assertEqual(len(s.generators), 2) 2537 if self.con.ods < fdb.ODS_FB_30: 2538 self.assertEqual(len(s.sysgenerators), 9) 2539 self.assertEqual(len(s.syssequences), 9) 2540 else: 2541 self.assertEqual(len(s.sysgenerators), 13) 2542 self.assertEqual(len(s.syssequences), 13) 2543 self.assertEqual(len(s.sequences), 2) 2544 self.assertEqual(len(s.domains), 15) 2545 if self.con.ods <= fdb.ODS_FB_20: 2546 self.assertEqual(len(s.sysdomains), 203) 2547 elif self.con.ods == fdb.ODS_FB_21: 2548 self.assertEqual(len(s.sysdomains), 227) 2549 elif self.con.ods == fdb.ODS_FB_25: 2550 self.assertEqual(len(s.sysdomains), 230) 2551 elif self.con.ods == fdb.ODS_FB_30: 2552 self.assertEqual(len(s.sysdomains), 277) 2553 else: 2554 self.assertEqual(len(s.sysdomains), 247) 2555 self.assertEqual(len(s.indices), 12) 2556 if self.con.ods <= fdb.ODS_FB_21: 2557 self.assertEqual(len(s.sysindices), 72) 2558 elif self.con.ods == fdb.ODS_FB_25: 2559 self.assertEqual(len(s.sysindices), 76) 2560 elif self.con.ods == fdb.ODS_FB_30: 2561 self.assertEqual(len(s.sysindices), 82) 2562 else: 2563 self.assertEqual(len(s.sysindices), 78) 2564 if self.con.ods < fdb.ODS_FB_30: 2565 self.assertEqual(len(s.tables), 15) 2566 else: 2567 self.assertEqual(len(s.tables), 16) 2568 if self.con.ods <= fdb.ODS_FB_20: 2569 self.assertEqual(len(s.systables), 33) 2570 elif self.con.ods == fdb.ODS_FB_21: 2571 self.assertEqual(len(s.systables), 40) 2572 elif self.con.ods == fdb.ODS_FB_25: 2573 self.assertEqual(len(s.systables), 42) 2574 elif self.con.ods == fdb.ODS_FB_30: 2575 self.assertEqual(len(s.systables), 50) 2576 else: 2577 self.assertEqual(len(s.systables), 44) 2578 self.assertEqual(len(s.views), 1) 2579 self.assertEqual(len(s.sysviews), 0) 2580 self.assertEqual(len(s.triggers), 6) 2581 if self.con.ods < fdb.ODS_FB_30: 2582 self.assertEqual(len(s.systriggers), 63) 2583 else: 2584 self.assertEqual(len(s.systriggers), 57) 2585 if self.con.ods < fdb.ODS_FB_30: 2586 self.assertEqual(len(s.procedures), 10) 2587 else: 2588 self.assertEqual(len(s.procedures), 11) 2589 self.assertEqual(len(s.sysprocedures), 0) 2590 if self.con.ods < fdb.ODS_FB_30: 2591 self.assertEqual(len(s.constraints), 82) 2592 else: 2593 self.assertEqual(len(s.constraints), 110) 2594 if self.con.ods <= fdb.ODS_FB_21: 2595 self.assertEqual(len(s.roles), 1) 2596 elif self.con.ods >= fdb.ODS_FB_25: 2597 self.assertEqual(len(s.roles), 2) 2598 if self.con.ods <= fdb.ODS_FB_20: 2599 self.assertEqual(len(s.dependencies), 163) 2600 elif self.con.ods == fdb.ODS_FB_21: 2601 self.assertEqual(len(s.dependencies), 157) 2602 elif self.con.ods == fdb.ODS_FB_25: 2603 self.assertEqual(len(s.dependencies), 163) 2604 elif self.con.ods >= fdb.ODS_FB_30: 2605 self.assertEqual(len(s.dependencies), 168) 2606 if self.con.ods < fdb.ODS_FB_30: 2607 self.assertEqual(len(s.functions), 0) 2608 else: 2609 self.assertEqual(len(s.functions), 6) 2610 if self.con.ods < fdb.ODS_FB_30: 2611 self.assertEqual(len(s.sysfunctions), 2) 2612 else: 2613 self.assertEqual(len(s.sysfunctions), 0) 2614 self.assertEqual(len(s.files), 0) 2615 # 2616 self.assertIsInstance(s.collations[0], sm.Collation) 2617 self.assertIsInstance(s.character_sets[0], sm.CharacterSet) 2618 self.assertIsInstance(s.exceptions[0], sm.DatabaseException) 2619 self.assertIsInstance(s.generators[0], sm.Sequence) 2620 self.assertIsInstance(s.sysgenerators[0], sm.Sequence) 2621 self.assertIsInstance(s.sequences[0], sm.Sequence) 2622 self.assertIsInstance(s.syssequences[0], sm.Sequence) 2623 self.assertIsInstance(s.domains[0], sm.Domain) 2624 self.assertIsInstance(s.sysdomains[0], sm.Domain) 2625 self.assertIsInstance(s.indices[0], sm.Index) 2626 self.assertIsInstance(s.sysindices[0], sm.Index) 2627 self.assertIsInstance(s.tables[0], sm.Table) 2628 self.assertIsInstance(s.systables[0], sm.Table) 2629 self.assertIsInstance(s.views[0], sm.View) 2630 if len(s.sysviews) > 0: 2631 self.assertIsInstance(s.sysviews[0],sm.View) 2632 self.assertIsInstance(s.triggers[0], sm.Trigger) 2633 self.assertIsInstance(s.systriggers[0], sm.Trigger) 2634 self.assertIsInstance(s.procedures[0], sm.Procedure) 2635 if len(s.sysprocedures) > 0: 2636 self.assertIsInstance(s.sysprocedures[0],sm.Procedure) 2637 self.assertIsInstance(s.constraints[0], sm.Constraint) 2638 if len(s.roles) > 0: 2639 self.assertIsInstance(s.roles[0],sm.Role) 2640 self.assertIsInstance(s.dependencies[0], sm.Dependency) 2641 if self.con.ods < fdb.ODS_FB_30: 2642 self.assertIsInstance(s.sysfunctions[0], sm.Function) 2643 if len(s.files) > 0: 2644 self.assertIsInstance(s.files[0],sm.DatabaseFile) 2645 # 2646 self.assertEqual(s.get_collation('OCTETS').name, 'OCTETS') 2647 self.assertEqual(s.get_character_set('WIN1250').name, 'WIN1250') 2648 self.assertEqual(s.get_exception('UNKNOWN_EMP_ID').name, 'UNKNOWN_EMP_ID') 2649 self.assertEqual(s.get_generator('EMP_NO_GEN').name, 'EMP_NO_GEN') 2650 self.assertEqual(s.get_sequence('EMP_NO_GEN').name, 'EMP_NO_GEN') 2651 self.assertEqual(s.get_index('MINSALX').name, 'MINSALX') 2652 self.assertEqual(s.get_domain('FIRSTNAME').name, 'FIRSTNAME') 2653 self.assertEqual(s.get_table('COUNTRY').name, 'COUNTRY') 2654 self.assertEqual(s.get_view('PHONE_LIST').name, 'PHONE_LIST') 2655 self.assertEqual(s.get_trigger('SET_EMP_NO').name, 'SET_EMP_NO') 2656 self.assertEqual(s.get_procedure('GET_EMP_PROJ').name, 'GET_EMP_PROJ') 2657 self.assertEqual(s.get_constraint('INTEG_1').name, 'INTEG_1') 2658 #self.assertEqual(s.get_role('X').name,'X') 2659 if self.con.ods < fdb.ODS_FB_30: 2660 self.assertEqual(s.get_function('RDB$GET_CONTEXT').name, 'RDB$GET_CONTEXT') 2661 self.assertEqual(s.get_collation_by_id(0, 0).name, 'NONE') 2662 self.assertEqual(s.get_character_set_by_id(0).name, 'NONE') 2663 self.assertFalse(s.ismultifile()) 2664 # 2665 self.assertFalse(s.closed) 2666 # 2667 with self.assertRaises(fdb.ProgrammingError) as cm: 2668 s.close() 2669 self.assertTupleEqual(cm.exception.args, 2670 ("Call to 'close' not allowed for embedded Schema.",)) 2671 with self.assertRaises(fdb.ProgrammingError) as cm: 2672 s.bind(self.con) 2673 self.assertTupleEqual(cm.exception.args, 2674 ("Call to 'bind' not allowed for embedded Schema.",)) 2675 def testCollation(self): 2676 # System collation 2677 c = self.con.schema.get_collation('ES_ES') 2678 # common properties 2679 self.assertEqual(c.name, 'ES_ES') 2680 self.assertIsNone(c.description) 2681 self.assertListEqual(c.actions, ['comment']) 2682 self.assertTrue(c.issystemobject()) 2683 self.assertEqual(c.get_quoted_name(), 'ES_ES') 2684 self.assertListEqual(c.get_dependents(), []) 2685 self.assertListEqual(c.get_dependencies(), []) 2686 if self.con.ods < fdb.ODS_FB_30: 2687 self.assertIsNone(c.security_class) 2688 self.assertIsNone(c.owner_name) 2689 else: 2690 self.assertEqual(c.security_class, 'SQL$263') 2691 self.assertEqual(c.owner_name, 'SYSDBA') 2692 # 2693 self.assertEqual(c.id, 10) 2694 self.assertEqual(c.character_set.name, 'ISO8859_1') 2695 self.assertIsNone(c.base_collation) 2696 self.assertEqual(c.attributes, 1) 2697 if self.con.ods <= fdb.ODS_FB_20: 2698 self.assertIsNone(c.specific_attributes) 2699 elif self.con.ods > fdb.ODS_FB_20: 2700 self.assertEqual(c.specific_attributes, 2701 'DISABLE-COMPRESSIONS=1;SPECIALS-FIRST=1') 2702 self.assertIsNone(c.function_name) 2703 # User defined collation 2704 # create collation TEST_COLLATE 2705 # for win1250 2706 # from WIN_CZ no pad case insensitive accent insensitive 2707 # 'DISABLE-COMPRESSIONS=0;DISABLE-EXPANSIONS=0' 2708 c = self.con.schema.get_collation('TEST_COLLATE') 2709 # common properties 2710 self.assertEqual(c.name, 'TEST_COLLATE') 2711 self.assertIsNone(c.description) 2712 self.assertListEqual(c.actions, ['comment', 'create', 'drop']) 2713 self.assertFalse(c.issystemobject()) 2714 self.assertEqual(c.get_quoted_name(), 'TEST_COLLATE') 2715 self.assertListEqual(c.get_dependents(), []) 2716 self.assertListEqual(c.get_dependencies(), []) 2717 # 2718 self.assertEqual(c.id, 126) 2719 self.assertEqual(c.character_set.name, 'WIN1250') 2720 self.assertEqual(c.base_collation.name, 'WIN_CZ') 2721 self.assertEqual(c.attributes, 6) 2722 self.assertEqual(c.specific_attributes, 2723 'DISABLE-COMPRESSIONS=0;DISABLE-EXPANSIONS=0') 2724 self.assertIsNone(c.function_name) 2725 self.assertEqual(c.get_sql_for('create'), 2726 """CREATE COLLATION TEST_COLLATE 2727 FOR WIN1250 2728 FROM WIN_CZ 2729 NO PAD 2730 CASE INSENSITIVE 2731 ACCENT INSENSITIVE 2732 'DISABLE-COMPRESSIONS=0;DISABLE-EXPANSIONS=0'""") 2733 self.assertEqual(c.get_sql_for('drop'), "DROP COLLATION TEST_COLLATE") 2734 with self.assertRaises(fdb.ProgrammingError) as cm: 2735 c.get_sql_for('drop', badparam='') 2736 self.assertTupleEqual(cm.exception.args, 2737 ("Unsupported parameter(s) 'badparam'",)) 2738 self.assertEqual(c.get_sql_for('comment'), 2739 "COMMENT ON COLLATION TEST_COLLATE IS NULL") 2740 2741 def testCharacterSet(self): 2742 c = self.con.schema.get_character_set('UTF8') 2743 # common properties 2744 self.assertEqual(c.name, 'UTF8') 2745 self.assertIsNone(c.description) 2746 self.assertListEqual(c.actions, ['alter', 'comment']) 2747 self.assertTrue(c.issystemobject()) 2748 self.assertEqual(c.get_quoted_name(), 'UTF8') 2749 self.assertListEqual(c.get_dependents(), []) 2750 self.assertListEqual(c.get_dependencies(), []) 2751 if self.con.ods < fdb.ODS_FB_30: 2752 self.assertIsNone(c.security_class) 2753 self.assertIsNone(c.owner_name) 2754 else: 2755 self.assertEqual(c.security_class, 'SQL$166') 2756 self.assertEqual(c.owner_name, 'SYSDBA') 2757 # 2758 self.assertEqual(c.id, 4) 2759 self.assertEqual(c.bytes_per_character, 4) 2760 self.assertEqual(c.default_collate.name, 'UTF8') 2761 if self.con.ods <= fdb.ODS_FB_20: 2762 self.assertListEqual([x.name for x in c.collations], 2763 ['UTF8', 'UCS_BASIC', 'UNICODE']) 2764 elif self.con.ods == fdb.ODS_FB_21: 2765 self.assertListEqual([x.name for x in c.collations], 2766 ['UTF8', 'UCS_BASIC', 'UNICODE', 'UNICODE_CI']) 2767 elif self.con.ods >= fdb.ODS_FB_25: 2768 self.assertListEqual([x.name for x in c.collations], 2769 ['UTF8', 'UCS_BASIC', 'UNICODE', 'UNICODE_CI', 'UNICODE_CI_AI']) 2770 # 2771 self.assertEqual(c.get_sql_for('alter', collation='UCS_BASIC'), 2772 "ALTER CHARACTER SET UTF8 SET DEFAULT COLLATION UCS_BASIC") 2773 with self.assertRaises(fdb.ProgrammingError) as cm: 2774 c.get_sql_for('alter', badparam='UCS_BASIC') 2775 self.assertTupleEqual(cm.exception.args, 2776 ("Unsupported parameter(s) 'badparam'",)) 2777 with self.assertRaises(fdb.ProgrammingError) as cm: 2778 c.get_sql_for('alter') 2779 self.assertTupleEqual(cm.exception.args, 2780 ("Missing required parameter: 'collation'.",)) 2781 # 2782 self.assertEqual(c.get_sql_for('comment'), 2783 'COMMENT ON CHARACTER SET UTF8 IS NULL') 2784 # 2785 self.assertEqual(c.get_collation('UCS_BASIC').name, 'UCS_BASIC') 2786 self.assertEqual(c.get_collation_by_id(c.get_collation('UCS_BASIC').id).name, 2787 'UCS_BASIC') 2788 def testException(self): 2789 c = self.con.schema.get_exception('UNKNOWN_EMP_ID') 2790 # common properties 2791 self.assertEqual(c.name, 'UNKNOWN_EMP_ID') 2792 self.assertIsNone(c.description) 2793 self.assertListEqual(c.actions, 2794 ['comment', 'create', 'recreate', 'alter', 'create_or_alter', 'drop']) 2795 self.assertFalse(c.issystemobject()) 2796 self.assertEqual(c.get_quoted_name(), 'UNKNOWN_EMP_ID') 2797 d = c.get_dependents() 2798 self.assertEqual(len(d), 1) 2799 d = d[0] 2800 self.assertEqual(d.dependent_name, 'ADD_EMP_PROJ') 2801 self.assertEqual(d.dependent_type, 5) 2802 self.assertIsInstance(d.dependent, sm.Procedure) 2803 self.assertEqual(d.depended_on_name, 'UNKNOWN_EMP_ID') 2804 self.assertEqual(d.depended_on_type, 7) 2805 self.assertIsInstance(d.depended_on, sm.DatabaseException) 2806 self.assertListEqual(c.get_dependencies(), []) 2807 if self.con.ods < fdb.ODS_FB_30: 2808 self.assertIsNone(c.security_class) 2809 self.assertIsNone(c.owner_name) 2810 else: 2811 self.assertEqual(c.security_class, 'SQL$476') 2812 self.assertEqual(c.owner_name, 'SYSDBA') 2813 # 2814 self.assertEqual(c.id, 1) 2815 self.assertEqual(c.message, "Invalid employee number or project id.") 2816 # 2817 self.assertEqual(c.get_sql_for('create'), 2818 "CREATE EXCEPTION UNKNOWN_EMP_ID 'Invalid employee number or project id.'") 2819 self.assertEqual(c.get_sql_for('recreate'), 2820 "RECREATE EXCEPTION UNKNOWN_EMP_ID 'Invalid employee number or project id.'") 2821 self.assertEqual(c.get_sql_for('drop'), 2822 "DROP EXCEPTION UNKNOWN_EMP_ID") 2823 self.assertEqual(c.get_sql_for('alter', message="New message."), 2824 "ALTER EXCEPTION UNKNOWN_EMP_ID 'New message.'") 2825 with self.assertRaises(fdb.ProgrammingError) as cm: 2826 c.get_sql_for('alter', badparam="New message.") 2827 self.assertTupleEqual(cm.exception.args, 2828 ("Unsupported parameter(s) 'badparam'",)) 2829 with self.assertRaises(fdb.ProgrammingError) as cm: 2830 c.get_sql_for('alter') 2831 self.assertTupleEqual(cm.exception.args, 2832 ("Missing required parameter: 'message'.",)) 2833 self.assertEqual(c.get_sql_for('create_or_alter'), 2834 "CREATE OR ALTER EXCEPTION UNKNOWN_EMP_ID 'Invalid employee number or project id.'") 2835 self.assertEqual(c.get_sql_for('comment'), 2836 "COMMENT ON EXCEPTION UNKNOWN_EMP_ID IS NULL") 2837 def testSequence(self): 2838 # System generator 2839 c = self.con.schema.get_sequence('RDB$FIELD_NAME') 2840 # common properties 2841 self.assertEqual(c.name, 'RDB$FIELD_NAME') 2842 self.assertEqual(c.description, "Implicit domain name") 2843 self.assertListEqual(c.actions, ['comment']) 2844 self.assertTrue(c.issystemobject()) 2845 self.assertEqual(c.get_quoted_name(), 'RDB$FIELD_NAME') 2846 self.assertListEqual(c.get_dependents(), []) 2847 self.assertListEqual(c.get_dependencies(), []) 2848 # 2849 self.assertEqual(c.id, 6) 2850 # User generator 2851 c = self.con.schema.get_generator('EMP_NO_GEN') 2852 # common properties 2853 self.assertEqual(c.name, 'EMP_NO_GEN') 2854 self.assertIsNone(c.description) 2855 self.assertListEqual(c.actions, ['comment', 'create', 2856 'alter', 'drop']) 2857 self.assertFalse(c.issystemobject()) 2858 self.assertEqual(c.get_quoted_name(), 'EMP_NO_GEN') 2859 d = c.get_dependents() 2860 self.assertEqual(len(d), 1) 2861 d = d[0] 2862 self.assertEqual(d.dependent_name, 'SET_EMP_NO') 2863 self.assertEqual(d.dependent_type, 2) 2864 self.assertIsInstance(d.dependent, sm.Trigger) 2865 self.assertEqual(d.depended_on_name, 'EMP_NO_GEN') 2866 self.assertEqual(d.depended_on_type, 14) 2867 self.assertIsInstance(d.depended_on, sm.Sequence) 2868 self.assertListEqual(c.get_dependencies(), []) 2869 # 2870 if self.con.ods < fdb.ODS_FB_30: 2871 self.assertEqual(c.id, 10) 2872 self.assertIsNone(c.security_class) 2873 self.assertIsNone(c.owner_name) 2874 self.assertIsNone(c.inital_value) 2875 self.assertIsNone(c.increment) 2876 else: 2877 self.assertEqual(c.id, 12) 2878 self.assertEqual(c.security_class, 'SQL$429') 2879 self.assertEqual(c.owner_name, 'SYSDBA') 2880 self.assertEqual(c.inital_value, 0) 2881 self.assertEqual(c.increment, 1) 2882 self.assertEqual(c.value, 145) 2883 # 2884 self.assertEqual(c.get_sql_for('create'), "CREATE SEQUENCE EMP_NO_GEN") 2885 self.assertEqual(c.get_sql_for('drop'), "DROP SEQUENCE EMP_NO_GEN") 2886 self.assertEqual(c.get_sql_for('alter', value=10), 2887 "ALTER SEQUENCE EMP_NO_GEN RESTART WITH 10") 2888 with self.assertRaises(fdb.ProgrammingError) as cm: 2889 c.get_sql_for('alter', badparam=10) 2890 self.assertTupleEqual(cm.exception.args, 2891 ("Unsupported parameter(s) 'badparam'",)) 2892 with self.assertRaises(fdb.ProgrammingError) as cm: 2893 c.get_sql_for('alter') 2894 self.assertTupleEqual(cm.exception.args, 2895 ("Missing required parameter: 'value'.",)) 2896 self.assertEqual(c.get_sql_for('comment'), 2897 "COMMENT ON SEQUENCE EMP_NO_GEN IS NULL") 2898 c.schema.opt_generator_keyword = 'GENERATOR' 2899 self.assertEqual(c.get_sql_for('comment'), 2900 "COMMENT ON GENERATOR EMP_NO_GEN IS NULL") 2901 def testTableColumn(self): 2902 # System column 2903 c = self.con.schema.get_table('RDB$PAGES').get_column('RDB$PAGE_NUMBER') 2904 # common properties 2905 self.assertEqual(c.name, 'RDB$PAGE_NUMBER') 2906 self.assertIsNone(c.description) 2907 self.assertListEqual(c.actions, ['comment']) 2908 self.assertTrue(c.issystemobject()) 2909 self.assertEqual(c.get_quoted_name(), 'RDB$PAGE_NUMBER') 2910 self.assertListEqual(c.get_dependents(), []) 2911 self.assertListEqual(c.get_dependencies(), []) 2912 self.assertFalse(c.isidentity()) 2913 self.assertIsNone(c.generator) 2914 # User column 2915 c = self.con.schema.get_table('DEPARTMENT').get_column('PHONE_NO') 2916 # common properties 2917 self.assertEqual(c.name, 'PHONE_NO') 2918 self.assertIsNone(c.description) 2919 self.assertListEqual(c.actions, ['comment', 'alter', 'drop']) 2920 self.assertFalse(c.issystemobject()) 2921 self.assertEqual(c.get_quoted_name(), 'PHONE_NO') 2922 d = c.get_dependents() 2923 self.assertEqual(len(d), 1) 2924 d = d[0] 2925 self.assertEqual(d.dependent_name, 'PHONE_LIST') 2926 self.assertEqual(d.dependent_type, 1) 2927 self.assertIsInstance(d.dependent, sm.View) 2928 self.assertEqual(d.depended_on_name, 'DEPARTMENT') 2929 self.assertEqual(d.depended_on_type, 0) 2930 self.assertIsInstance(d.depended_on, sm.TableColumn) 2931 self.assertListEqual(c.get_dependencies(), []) 2932 # 2933 self.assertEqual(c.table.name, 'DEPARTMENT') 2934 self.assertEqual(c.domain.name, 'PHONENUMBER') 2935 self.assertEqual(c.position, 6) 2936 self.assertIsNone(c.security_class) 2937 self.assertEqual(c.default, "'555-1234'") 2938 self.assertIsNone(c.collation) 2939 self.assertEqual(c.datatype, 'VARCHAR(20)') 2940 # 2941 self.assertTrue(c.isnullable()) 2942 self.assertFalse(c.iscomputed()) 2943 self.assertTrue(c.isdomainbased()) 2944 self.assertTrue(c.has_default()) 2945 self.assertIsNone(c.get_computedby()) 2946 # 2947 self.assertEqual(c.get_sql_for('comment'), 2948 "COMMENT ON COLUMN DEPARTMENT.PHONE_NO IS NULL") 2949 self.assertEqual(c.get_sql_for('drop'), 2950 "ALTER TABLE DEPARTMENT DROP PHONE_NO") 2951 self.assertEqual(c.get_sql_for('alter', name='NewName'), 2952 'ALTER TABLE DEPARTMENT ALTER COLUMN PHONE_NO TO "NewName"') 2953 self.assertEqual(c.get_sql_for('alter', position=2), 2954 "ALTER TABLE DEPARTMENT ALTER COLUMN PHONE_NO POSITION 2") 2955 self.assertEqual(c.get_sql_for('alter', datatype='VARCHAR(25)'), 2956 "ALTER TABLE DEPARTMENT ALTER COLUMN PHONE_NO TYPE VARCHAR(25)") 2957 with self.assertRaises(fdb.ProgrammingError) as cm: 2958 c.get_sql_for('alter', badparam=10) 2959 self.assertTupleEqual(cm.exception.args, ("Unsupported parameter(s) 'badparam'",)) 2960 with self.assertRaises(fdb.ProgrammingError) as cm: 2961 c.get_sql_for('alter') 2962 self.assertTupleEqual(cm.exception.args, ("Parameter required.",)) 2963 with self.assertRaises(fdb.ProgrammingError) as cm: 2964 c.get_sql_for('alter', expression='(1+1)') 2965 self.assertTupleEqual(cm.exception.args, 2966 ("Change from persistent column to computed is not allowed.",)) 2967 # Computed column 2968 c = self.con.schema.get_table('EMPLOYEE').get_column('FULL_NAME') 2969 self.assertTrue(c.isnullable()) 2970 self.assertTrue(c.iscomputed()) 2971 self.assertFalse(c.isdomainbased()) 2972 self.assertFalse(c.has_default()) 2973 self.assertEqual(c.get_computedby(), "(last_name || ', ' || first_name)") 2974 if self.con.ods < fdb.ODS_FB_30: 2975 self.assertEqual(c.datatype, 'VARCHAR(0)') 2976 else: 2977 self.assertEqual(c.datatype, 'VARCHAR(37)') 2978 # 2979 self.assertEqual(c.get_sql_for('alter', datatype='VARCHAR(50)', 2980 expression="(first_name || ', ' || last_name)"), 2981 "ALTER TABLE EMPLOYEE ALTER COLUMN FULL_NAME TYPE VARCHAR(50) " \ 2982 "COMPUTED BY (first_name || ', ' || last_name)") 2983 2984 with self.assertRaises(fdb.ProgrammingError) as cm: 2985 c.get_sql_for('alter', datatype='VARCHAR(50)') 2986 self.assertTupleEqual(cm.exception.args, 2987 ("Change from computed column to persistent is not allowed.",)) 2988 # Array column 2989 c = self.con.schema.get_table('AR').get_column('C2') 2990 self.assertEqual(c.datatype, 'INTEGER[4, 0:3, 2]') 2991 # Identity column 2992 if self.con.ods >= fdb.ODS_FB_30: 2993 c = self.con.schema.get_table('T5').get_column('ID') 2994 self.assertTrue(c.isidentity()) 2995 self.assertTrue(c.generator.isidentity()) 2996 self.assertEqual(c.identity_type, 1) 2997 # 2998 self.assertEqual(c.get_sql_for('alter', restart=None), 2999 "ALTER TABLE T5 ALTER COLUMN ID RESTART") 3000 self.assertEqual(c.get_sql_for('alter', restart=100), 3001 "ALTER TABLE T5 ALTER COLUMN ID RESTART WITH 100") 3002 def testIndex(self): 3003 # System index 3004 c = self.con.schema.get_index('RDB$INDEX_0') 3005 # common properties 3006 self.assertEqual(c.name, 'RDB$INDEX_0') 3007 self.assertIsNone(c.description) 3008 self.assertListEqual(c.actions, ['activate', 'recompute', 'comment']) 3009 self.assertTrue(c.issystemobject()) 3010 self.assertEqual(c.get_quoted_name(), 'RDB$INDEX_0') 3011 self.assertListEqual(c.get_dependents(), []) 3012 self.assertListEqual(c.get_dependencies(), []) 3013 # 3014 self.assertEqual(c.table.name, 'RDB$RELATIONS') 3015 self.assertListEqual(c.segment_names, ['RDB$RELATION_NAME']) 3016 # user index 3017 c = self.con.schema.get_index('MAXSALX') 3018 # common properties 3019 self.assertEqual(c.name, 'MAXSALX') 3020 self.assertIsNone(c.description) 3021 self.assertListEqual(c.actions, ['activate', 'recompute', 'comment', 'create', 'deactivate', 'drop']) 3022 self.assertFalse(c.issystemobject()) 3023 self.assertEqual(c.get_quoted_name(), 'MAXSALX') 3024 self.assertListEqual(c.get_dependents(), []) 3025 self.assertListEqual(c.get_dependencies(), []) 3026 # 3027 self.assertEqual(c.id, 3) 3028 self.assertEqual(c.table.name, 'JOB') 3029 self.assertEqual(c.index_type, 'DESCENDING') 3030 self.assertIsNone(c.partner_index) 3031 self.assertIsNone(c.expression) 3032 # startswith() is necessary, because Python 3 returns more precise value. 3033 self.assertTrue(str(c.statistics).startswith('0.0384615398943')) 3034 self.assertListEqual(c.segment_names, ['JOB_COUNTRY', 'MAX_SALARY']) 3035 self.assertEqual(len(c.segments), 2) 3036 for segment in c.segments: 3037 self.assertIsInstance(segment, sm.TableColumn) 3038 self.assertEqual(c.segments[0].name, 'JOB_COUNTRY') 3039 self.assertEqual(c.segments[1].name, 'MAX_SALARY') 3040 3041 if self.con.ods <= fdb.ODS_FB_20: 3042 self.assertListEqual(c.segment_statistics, [None, None]) 3043 elif self.con.ods > fdb.ODS_FB_20: 3044 self.assertListEqual(c.segment_statistics, 3045 [0.1428571492433548, 0.03846153989434242]) 3046 self.assertIsNone(c.constraint) 3047 # 3048 self.assertFalse(c.isexpression()) 3049 self.assertFalse(c.isunique()) 3050 self.assertFalse(c.isinactive()) 3051 self.assertFalse(c.isenforcer()) 3052 # 3053 self.assertEqual(c.get_sql_for('create'), 3054 """CREATE DESCENDING INDEX MAXSALX ON JOB (JOB_COUNTRY,MAX_SALARY)""") 3055 self.assertEqual(c.get_sql_for('activate'), "ALTER INDEX MAXSALX ACTIVE") 3056 self.assertEqual(c.get_sql_for('deactivate'), "ALTER INDEX MAXSALX INACTIVE") 3057 self.assertEqual(c.get_sql_for('recompute'), "SET STATISTICS INDEX MAXSALX") 3058 self.assertEqual(c.get_sql_for('drop'), "DROP INDEX MAXSALX") 3059 self.assertEqual(c.get_sql_for('comment'), 3060 "COMMENT ON INDEX MAXSALX IS NULL") 3061 # Constraint index 3062 c = self.con.schema.get_index('RDB$FOREIGN6') 3063 # common properties 3064 self.assertEqual(c.name, 'RDB$FOREIGN6') 3065 self.assertTrue(c.issystemobject()) 3066 self.assertTrue(c.isenforcer()) 3067 self.assertEqual(c.partner_index.name, 'RDB$PRIMARY5') 3068 self.assertEqual(c.constraint.name, 'INTEG_17') 3069 def testViewColumn(self): 3070 c = self.con.schema.get_view('PHONE_LIST').get_column('LAST_NAME') 3071 # common properties 3072 self.assertEqual(c.name, 'LAST_NAME') 3073 self.assertIsNone(c.description) 3074 self.assertListEqual(c.actions, ['comment']) 3075 self.assertFalse(c.issystemobject()) 3076 self.assertEqual(c.get_quoted_name(), 'LAST_NAME') 3077 self.assertListEqual(c.get_dependents(), []) 3078 d = c.get_dependencies() 3079 self.assertEqual(len(d), 1) 3080 d = d[0] 3081 self.assertEqual(d.dependent_name, 'PHONE_LIST') 3082 self.assertEqual(d.dependent_type, 1) 3083 self.assertIsInstance(d.dependent, sm.View) 3084 self.assertEqual(d.field_name, 'LAST_NAME') 3085 self.assertEqual(d.depended_on_name, 'EMPLOYEE') 3086 self.assertEqual(d.depended_on_type, 0) 3087 self.assertIsInstance(d.depended_on, sm.TableColumn) 3088 self.assertEqual(d.depended_on.name, 'LAST_NAME') 3089 self.assertEqual(d.depended_on.table.name, 'EMPLOYEE') 3090 # 3091 self.assertEqual(c.view.name, 'PHONE_LIST') 3092 self.assertEqual(c.base_field.name, 'LAST_NAME') 3093 self.assertEqual(c.base_field.table.name, 'EMPLOYEE') 3094 self.assertEqual(c.domain.name, 'LASTNAME') 3095 self.assertEqual(c.position, 2) 3096 self.assertIsNone(c.security_class) 3097 self.assertEqual(c.collation.name, 'NONE') 3098 self.assertEqual(c.datatype, 'VARCHAR(20)') 3099 # 3100 self.assertTrue(c.isnullable()) 3101 # 3102 self.assertEqual(c.get_sql_for('comment'), 3103 "COMMENT ON COLUMN PHONE_LIST.LAST_NAME IS NULL") 3104 def testDomain(self): 3105 # System domain 3106 c = self.con.schema.get_domain('RDB$6') 3107 # common properties 3108 self.assertEqual(c.name, 'RDB$6') 3109 self.assertIsNone(c.description) 3110 self.assertListEqual(c.actions, ['comment']) 3111 self.assertTrue(c.issystemobject()) 3112 self.assertEqual(c.get_quoted_name(), 'RDB$6') 3113 self.assertListEqual(c.get_dependents(), []) 3114 self.assertListEqual(c.get_dependencies(), []) 3115 if self.con.ods < fdb.ODS_FB_30: 3116 self.assertIsNone(c.security_class) 3117 self.assertIsNone(c.owner_name) 3118 else: 3119 self.assertEqual(c.security_class, 'SQL$439') 3120 self.assertEqual(c.owner_name, 'SYSDBA') 3121 # User domain 3122 c = self.con.schema.get_domain('PRODTYPE') 3123 # common properties 3124 self.assertEqual(c.name, 'PRODTYPE') 3125 self.assertIsNone(c.description) 3126 self.assertListEqual(c.actions, ['comment', 'create', 3127 'alter', 'drop']) 3128 self.assertFalse(c.issystemobject()) 3129 self.assertEqual(c.get_quoted_name(), 'PRODTYPE') 3130 self.assertListEqual(c.get_dependents(), []) 3131 self.assertListEqual(c.get_dependencies(), []) 3132 # 3133 self.assertIsNone(c.expression) 3134 self.assertEqual(c.validation, 3135 "CHECK (VALUE IN ('software', 'hardware', 'other', 'N/A'))") 3136 self.assertEqual(c.default, "'software'") 3137 self.assertEqual(c.length, 12) 3138 self.assertEqual(c.scale, 0) 3139 self.assertEqual(c.field_type, 37) 3140 self.assertEqual(c.sub_type, 0) 3141 self.assertIsNone(c.segment_length) 3142 self.assertIsNone(c.external_length) 3143 self.assertIsNone(c.external_scale) 3144 self.assertIsNone(c.external_type) 3145 self.assertListEqual(c.dimensions, []) 3146 self.assertEqual(c.character_length, 12) 3147 self.assertEqual(c.collation.name, 'NONE') 3148 self.assertEqual(c.character_set.name, 'NONE') 3149 self.assertIsNone(c.precision) 3150 self.assertEqual(c.datatype, 'VARCHAR(12)') 3151 # 3152 self.assertFalse(c.isnullable()) 3153 self.assertFalse(c.iscomputed()) 3154 self.assertTrue(c.isvalidated()) 3155 self.assertFalse(c.isarray()) 3156 self.assertTrue(c.has_default()) 3157 # 3158 self.assertEqual(c.get_sql_for('create'), 3159 "CREATE DOMAIN PRODTYPE AS VARCHAR(12) DEFAULT 'software' " \ 3160 "NOT NULL CHECK (VALUE IN ('software', 'hardware', 'other', 'N/A'))") 3161 self.assertEqual(c.get_sql_for('drop'), "DROP DOMAIN PRODTYPE") 3162 self.assertEqual(c.get_sql_for('alter', name='New_name'), 3163 'ALTER DOMAIN PRODTYPE TO "New_name"') 3164 self.assertEqual(c.get_sql_for('alter', default="'New_default'"), 3165 "ALTER DOMAIN PRODTYPE SET DEFAULT 'New_default'") 3166 self.assertEqual(c.get_sql_for('alter', check="VALUE STARTS WITH 'X'"), 3167 "ALTER DOMAIN PRODTYPE ADD CHECK (VALUE STARTS WITH 'X')") 3168 self.assertEqual(c.get_sql_for('alter', datatype='VARCHAR(30)'), 3169 "ALTER DOMAIN PRODTYPE TYPE VARCHAR(30)") 3170 with self.assertRaises(fdb.ProgrammingError) as cm: 3171 c.get_sql_for('alter', badparam=10) 3172 self.assertTupleEqual(cm.exception.args, 3173 ("Unsupported parameter(s) 'badparam'",)) 3174 with self.assertRaises(fdb.ProgrammingError) as cm: 3175 c.get_sql_for('alter') 3176 self.assertTupleEqual(cm.exception.args, ("Parameter required.",)) 3177 # Domain with quoted name 3178 c = self.con.schema.get_domain('FIRSTNAME') 3179 self.assertEqual(c.name, 'FIRSTNAME') 3180 self.assertEqual(c.get_quoted_name(), '"FIRSTNAME"') 3181 self.assertEqual(c.get_sql_for('create'), 3182 'CREATE DOMAIN "FIRSTNAME" AS VARCHAR(15)') 3183 self.assertEqual(c.get_sql_for('comment'), 3184 'COMMENT ON DOMAIN "FIRSTNAME" IS NULL') 3185 def testDependency(self): 3186 l = self.con.schema.get_table('DEPARTMENT').get_dependents() 3187 self.assertEqual(len(l), 18) 3188 c = l[0] if self.con.ods < fdb.ODS_FB_30 else l[3] 3189 # common properties 3190 self.assertIsNone(c.name) 3191 self.assertIsNone(c.description) 3192 self.assertListEqual(c.actions, []) 3193 self.assertTrue(c.issystemobject()) 3194 self.assertIsNone(c.get_quoted_name()) 3195 self.assertListEqual(c.get_dependents(), []) 3196 self.assertListEqual(c.get_dependencies(), []) 3197 self.assertIsNone(c.package) 3198 self.assertFalse(c.ispackaged()) 3199 # 3200 self.assertEqual(c.dependent_name, 'PHONE_LIST') 3201 self.assertEqual(c.dependent_type, 1) 3202 self.assertIsInstance(c.dependent, sm.View) 3203 self.assertEqual(c.dependent.name, 'PHONE_LIST') 3204 self.assertEqual(c.field_name, 'DEPT_NO') 3205 self.assertEqual(c.depended_on_name, 'DEPARTMENT') 3206 self.assertEqual(c.depended_on_type, 0) 3207 self.assertIsInstance(c.depended_on, sm.TableColumn) 3208 self.assertEqual(c.depended_on.name, 'DEPT_NO') 3209 # 3210 if self.con.engine_version >= 3.0: 3211 self.assertListEqual(c.get_dependents(), []) 3212 l = self.con.schema.get_package('TEST2').get_dependencies() 3213 self.assertEqual(len(l), 2) 3214 x = l[0] 3215 self.assertEqual(x.depended_on.name, 'FN') 3216 self.assertFalse(x.depended_on.ispackaged()) 3217 x = l[1] 3218 self.assertEqual(x.depended_on.name, 'F') 3219 self.assertTrue(x.depended_on.ispackaged()) 3220 self.assertIsInstance(x.package, sm.Package) 3221 def testConstraint(self): 3222 # Common / PRIMARY KEY 3223 c = self.con.schema.get_table('CUSTOMER').primary_key 3224 # common properties 3225 self.assertEqual(c.name, 'INTEG_60') 3226 self.assertIsNone(c.description) 3227 self.assertListEqual(c.actions, ['create', 'drop']) 3228 self.assertFalse(c.issystemobject()) 3229 self.assertEqual(c.get_quoted_name(), 'INTEG_60') 3230 self.assertListEqual(c.get_dependents(), []) 3231 self.assertListEqual(c.get_dependencies(), []) 3232 # 3233 self.assertEqual(c.constraint_type, 'PRIMARY KEY') 3234 self.assertEqual(c.table.name, 'CUSTOMER') 3235 self.assertEqual(c.index.name, 'RDB$PRIMARY22') 3236 self.assertListEqual(c.trigger_names, []) 3237 self.assertListEqual(c.triggers, []) 3238 self.assertIsNone(c.column_name) 3239 self.assertIsNone(c.partner_constraint) 3240 self.assertIsNone(c.match_option) 3241 self.assertIsNone(c.update_rule) 3242 self.assertIsNone(c.delete_rule) 3243 # 3244 self.assertFalse(c.isnotnull()) 3245 self.assertTrue(c.ispkey()) 3246 self.assertFalse(c.isfkey()) 3247 self.assertFalse(c.isunique()) 3248 self.assertFalse(c.ischeck()) 3249 self.assertFalse(c.isdeferrable()) 3250 self.assertFalse(c.isdeferred()) 3251 # 3252 self.assertEqual(c.get_sql_for('create'), 3253 "ALTER TABLE CUSTOMER ADD PRIMARY KEY (CUST_NO)") 3254 self.assertEqual(c.get_sql_for('drop'), 3255 "ALTER TABLE CUSTOMER DROP CONSTRAINT INTEG_60") 3256 # FOREIGN KEY 3257 c = self.con.schema.get_table('CUSTOMER').foreign_keys[0] 3258 # 3259 self.assertListEqual(c.actions, ['create', 'drop']) 3260 self.assertEqual(c.constraint_type, 'FOREIGN KEY') 3261 self.assertEqual(c.table.name, 'CUSTOMER') 3262 self.assertEqual(c.index.name, 'RDB$FOREIGN23') 3263 self.assertListEqual(c.trigger_names, []) 3264 self.assertListEqual(c.triggers, []) 3265 self.assertIsNone(c.column_name) 3266 self.assertEqual(c.partner_constraint.name, 'INTEG_2') 3267 self.assertEqual(c.match_option, 'FULL') 3268 self.assertEqual(c.update_rule, 'RESTRICT') 3269 self.assertEqual(c.delete_rule, 'RESTRICT') 3270 # 3271 self.assertFalse(c.isnotnull()) 3272 self.assertFalse(c.ispkey()) 3273 self.assertTrue(c.isfkey()) 3274 self.assertFalse(c.isunique()) 3275 self.assertFalse(c.ischeck()) 3276 # 3277 self.assertEqual(c.get_sql_for('create'), 3278 """ALTER TABLE CUSTOMER ADD FOREIGN KEY (COUNTRY) 3279 REFERENCES COUNTRY (COUNTRY)""") 3280 # CHECK 3281 c = self.con.schema.get_constraint('INTEG_59') 3282 # 3283 self.assertListEqual(c.actions, ['create', 'drop']) 3284 self.assertEqual(c.constraint_type, 'CHECK') 3285 self.assertEqual(c.table.name, 'CUSTOMER') 3286 self.assertIsNone(c.index) 3287 self.assertListEqual(c.trigger_names, ['CHECK_9', 'CHECK_10']) 3288 self.assertEqual(c.triggers[0].name, 'CHECK_9') 3289 self.assertEqual(c.triggers[1].name, 'CHECK_10') 3290 self.assertIsNone(c.column_name) 3291 self.assertIsNone(c.partner_constraint) 3292 self.assertIsNone(c.match_option) 3293 self.assertIsNone(c.update_rule) 3294 self.assertIsNone(c.delete_rule) 3295 # 3296 self.assertFalse(c.isnotnull()) 3297 self.assertFalse(c.ispkey()) 3298 self.assertFalse(c.isfkey()) 3299 self.assertFalse(c.isunique()) 3300 self.assertTrue(c.ischeck()) 3301 # 3302 self.assertEqual(c.get_sql_for('create'), 3303 "ALTER TABLE CUSTOMER ADD CHECK (on_hold IS NULL OR on_hold = '*')") 3304 # UNIQUE 3305 c = self.con.schema.get_constraint('INTEG_15') 3306 # 3307 self.assertListEqual(c.actions, ['create', 'drop']) 3308 self.assertEqual(c.constraint_type, 'UNIQUE') 3309 self.assertEqual(c.table.name, 'DEPARTMENT') 3310 self.assertEqual(c.index.name, 'RDB$4') 3311 self.assertListEqual(c.trigger_names, []) 3312 self.assertListEqual(c.triggers, []) 3313 self.assertIsNone(c.column_name) 3314 self.assertIsNone(c.partner_constraint) 3315 self.assertIsNone(c.match_option) 3316 self.assertIsNone(c.update_rule) 3317 self.assertIsNone(c.delete_rule) 3318 # 3319 self.assertFalse(c.isnotnull()) 3320 self.assertFalse(c.ispkey()) 3321 self.assertFalse(c.isfkey()) 3322 self.assertTrue(c.isunique()) 3323 self.assertFalse(c.ischeck()) 3324 # 3325 self.assertEqual(c.get_sql_for('create'), 3326 "ALTER TABLE DEPARTMENT ADD UNIQUE (DEPARTMENT)") 3327 # NOT NULL 3328 c = self.con.schema.get_constraint('INTEG_13') 3329 # 3330 self.assertListEqual(c.actions, []) 3331 self.assertEqual(c.constraint_type, 'NOT NULL') 3332 self.assertEqual(c.table.name, 'DEPARTMENT') 3333 self.assertIsNone(c.index) 3334 self.assertListEqual(c.trigger_names, []) 3335 self.assertListEqual(c.triggers, []) 3336 self.assertEqual(c.column_name, 'DEPT_NO') 3337 self.assertIsNone(c.partner_constraint) 3338 self.assertIsNone(c.match_option) 3339 self.assertIsNone(c.update_rule) 3340 self.assertIsNone(c.delete_rule) 3341 # 3342 self.assertTrue(c.isnotnull()) 3343 self.assertFalse(c.ispkey()) 3344 self.assertFalse(c.isfkey()) 3345 self.assertFalse(c.isunique()) 3346 self.assertFalse(c.ischeck()) 3347 def testTable(self): 3348 # System table 3349 c = self.con.schema.get_table('RDB$PAGES') 3350 # common properties 3351 self.assertEqual(c.name, 'RDB$PAGES') 3352 self.assertIsNone(c.description) 3353 self.assertListEqual(c.actions, ['comment']) 3354 self.assertTrue(c.issystemobject()) 3355 self.assertEqual(c.get_quoted_name(), 'RDB$PAGES') 3356 self.assertListEqual(c.get_dependents(), []) 3357 self.assertListEqual(c.get_dependencies(), []) 3358 # User table 3359 c = self.con.schema.get_table('EMPLOYEE') 3360 # common properties 3361 self.assertEqual(c.name, 'EMPLOYEE') 3362 self.assertIsNone(c.description) 3363 self.assertListEqual(c.actions, ['comment', 'create', 3364 'recreate', 'drop']) 3365 self.assertFalse(c.issystemobject()) 3366 self.assertEqual(c.get_quoted_name(), 'EMPLOYEE') 3367 d = c.get_dependents() 3368 if self.con.ods <= fdb.ODS_FB_20: 3369 self.assertListEqual([(x.dependent_name, x.dependent_type) for x in d], 3370 [('RDB$9', 3), ('RDB$9', 3), ('PHONE_LIST', 1), 3371 ('PHONE_LIST', 1), ('PHONE_LIST', 1), ('PHONE_LIST', 1), 3372 ('PHONE_LIST', 1), ('PHONE_LIST', 1), ('CHECK_3', 2), 3373 ('CHECK_3', 2), ('CHECK_3', 2), ('CHECK_3', 2), 3374 ('CHECK_4', 2), ('CHECK_4', 2), ('CHECK_4', 2), 3375 ('CHECK_4', 2), ('SET_EMP_NO', 2), ('SAVE_SALARY_CHANGE', 2), 3376 ('SAVE_SALARY_CHANGE', 2), ('DELETE_EMPLOYEE', 5), 3377 ('DELETE_EMPLOYEE', 5), ('ORG_CHART', 5), ('ORG_CHART', 5), 3378 ('ORG_CHART', 5), ('ORG_CHART', 5), ('ORG_CHART', 5)]) 3379 elif self.con.ods == fdb.ODS_FB_21: 3380 self.assertListEqual([(x.dependent_name, x.dependent_type) for x in d], 3381 [('PHONE_LIST', 1), ('PHONE_LIST', 1), ('PHONE_LIST', 1), 3382 ('PHONE_LIST', 1), ('PHONE_LIST', 1), ('CHECK_3', 2), 3383 ('CHECK_3', 2), ('CHECK_3', 2), ('CHECK_3', 2), 3384 ('CHECK_4', 2), ('CHECK_4', 2), ('CHECK_4', 2), 3385 ('CHECK_4', 2), ('SET_EMP_NO', 2), ('SAVE_SALARY_CHANGE', 2), 3386 ('SAVE_SALARY_CHANGE', 2), ('PHONE_LIST', 1), 3387 ('DELETE_EMPLOYEE', 5), ('DELETE_EMPLOYEE', 5), 3388 ('ORG_CHART', 5), ('ORG_CHART', 5), ('ORG_CHART', 5), 3389 ('ORG_CHART', 5), ('ORG_CHART', 5)]) 3390 elif self.con.ods == fdb.ODS_FB_25: 3391 self.assertListEqual([(x.dependent_name, x.dependent_type) for x in d], 3392 [('RDB$9', 3), ('RDB$9', 3), ('PHONE_LIST', 1), 3393 ('PHONE_LIST', 1), ('PHONE_LIST', 1), ('CHECK_3', 2), 3394 ('CHECK_3', 2), ('CHECK_3', 2), ('CHECK_3', 2), ('CHECK_4', 2), 3395 ('CHECK_4', 2), ('CHECK_4', 2), ('CHECK_4', 2), ('SET_EMP_NO', 2), 3396 ('SAVE_SALARY_CHANGE', 2), ('PHONE_LIST', 1), ('PHONE_LIST', 1), 3397 ('SAVE_SALARY_CHANGE', 2), ('PHONE_LIST', 1), ('ORG_CHART', 5), 3398 ('ORG_CHART', 5), ('ORG_CHART', 5), ('ORG_CHART', 5), ('ORG_CHART', 5), 3399 ('DELETE_EMPLOYEE', 5), ('DELETE_EMPLOYEE', 5)]) 3400 elif self.con.ods >= fdb.ODS_FB_30: 3401 self.assertListEqual([(x.dependent_name, x.dependent_type) for x in d], 3402 [('SAVE_SALARY_CHANGE', 2), ('SAVE_SALARY_CHANGE', 2), ('CHECK_3', 2), 3403 ('CHECK_3', 2), ('CHECK_3', 2), ('CHECK_3', 2), ('CHECK_4', 2), 3404 ('CHECK_4', 2), ('CHECK_4', 2), ('CHECK_4', 2), ('PHONE_LIST', 1), 3405 ('PHONE_LIST', 1), ('PHONE_LIST', 1), ('PHONE_LIST', 1), ('PHONE_LIST', 1), 3406 ('PHONE_LIST', 1), ('DELETE_EMPLOYEE', 5), ('DELETE_EMPLOYEE', 5), 3407 ('ORG_CHART', 5), ('ORG_CHART', 5), ('ORG_CHART', 5), ('ORG_CHART', 5), 3408 ('ORG_CHART', 5), ('RDB$9', 3), ('RDB$9', 3), ('SET_EMP_NO', 2)]) 3409 self.assertListEqual(c.get_dependencies(), []) 3410 # 3411 self.assertEqual(c.id, 131) 3412 self.assertEqual(c.dbkey_length, 8) 3413 if self.con.ods <= fdb.ODS_FB_20: 3414 self.assertEqual(c.format, 1) 3415 elif (self.con.ods > fdb.ODS_FB_20) and (self.con.ods < fdb.ODS_FB_30): 3416 self.assertEqual(c.format, 2) 3417 elif self.con.ods >= fdb.ODS_FB_30: 3418 self.assertEqual(c.format, 1) 3419 self.assertEqual(c.table_type, 'PERSISTENT') 3420 if self.con.ods <= fdb.ODS_FB_21: 3421 self.assertEqual(c.security_class, 'SQL$EMPLOYEE') 3422 elif self.con.ods == fdb.ODS_FB_25: 3423 self.assertEqual(c.security_class, 'SQL$7') 3424 elif self.con.ods == fdb.ODS_FB_30: 3425 self.assertEqual(c.security_class, 'SQL$440') 3426 else: 3427 self.assertEqual(c.security_class, 'SQL$482') 3428 self.assertIsNone(c.external_file) 3429 self.assertEqual(c.owner_name, 'SYSDBA') 3430 if self.con.ods <= fdb.ODS_FB_20: 3431 self.assertEqual(c.default_class, 'SQL$DEFAULT5') 3432 elif (self.con.ods > fdb.ODS_FB_20) and (self.con.ods < fdb.ODS_FB_30): 3433 self.assertEqual(c.default_class, 'SQL$DEFAULT7') 3434 elif self.con.ods >= fdb.ODS_FB_30: 3435 self.assertEqual(c.default_class, 'SQL$DEFAULT54') 3436 self.assertEqual(c.flags, 1) 3437 self.assertEqual(c.primary_key.name, 'INTEG_27') 3438 self.assertListEqual([x.name for x in c.foreign_keys], 3439 ['INTEG_28', 'INTEG_29']) 3440 self.assertListEqual([x.name for x in c.columns], 3441 ['EMP_NO', 'FIRST_NAME', 'LAST_NAME', 'PHONE_EXT', 3442 'HIRE_DATE', 'DEPT_NO', 'JOB_CODE', 'JOB_GRADE', 3443 'JOB_COUNTRY', 'SALARY', 'FULL_NAME']) 3444 self.assertListEqual([x.name for x in c.constraints], 3445 ['INTEG_18', 'INTEG_19', 'INTEG_20', 'INTEG_21', 3446 'INTEG_22', 'INTEG_23', 'INTEG_24', 'INTEG_25', 3447 'INTEG_26', 'INTEG_27', 'INTEG_28', 'INTEG_29', 3448 'INTEG_30']) 3449 self.assertListEqual([x.name for x in c.indices], 3450 ['NAMEX', 'RDB$PRIMARY7', 'RDB$FOREIGN8', 'RDB$FOREIGN9']) 3451 self.assertListEqual([x.name for x in c.triggers], 3452 ['SET_EMP_NO', 'SAVE_SALARY_CHANGE']) 3453 # 3454 self.assertEqual(c.get_column('EMP_NO').name, 'EMP_NO') 3455 self.assertFalse(c.isgtt()) 3456 self.assertTrue(c.ispersistent()) 3457 self.assertFalse(c.isexternal()) 3458 self.assertTrue(c.has_pkey()) 3459 self.assertTrue(c.has_fkey()) 3460 # 3461 self.assertEqual(c.get_sql_for('create'), """CREATE TABLE EMPLOYEE ( 3462 EMP_NO EMPNO NOT NULL, 3463 FIRST_NAME "FIRSTNAME" NOT NULL, 3464 LAST_NAME "LASTNAME" NOT NULL, 3465 PHONE_EXT VARCHAR(4), 3466 HIRE_DATE TIMESTAMP DEFAULT 'NOW' NOT NULL, 3467 DEPT_NO DEPTNO NOT NULL, 3468 JOB_CODE JOBCODE NOT NULL, 3469 JOB_GRADE JOBGRADE NOT NULL, 3470 JOB_COUNTRY COUNTRYNAME NOT NULL, 3471 SALARY SALARY NOT NULL, 3472 FULL_NAME COMPUTED BY (last_name || ', ' || first_name), 3473 PRIMARY KEY (EMP_NO) 3474)""") 3475 self.assertEqual(c.get_sql_for('create', no_pk=True), """CREATE TABLE EMPLOYEE ( 3476 EMP_NO EMPNO NOT NULL, 3477 FIRST_NAME "FIRSTNAME" NOT NULL, 3478 LAST_NAME "LASTNAME" NOT NULL, 3479 PHONE_EXT VARCHAR(4), 3480 HIRE_DATE TIMESTAMP DEFAULT 'NOW' NOT NULL, 3481 DEPT_NO DEPTNO NOT NULL, 3482 JOB_CODE JOBCODE NOT NULL, 3483 JOB_GRADE JOBGRADE NOT NULL, 3484 JOB_COUNTRY COUNTRYNAME NOT NULL, 3485 SALARY SALARY NOT NULL, 3486 FULL_NAME COMPUTED BY (last_name || ', ' || first_name) 3487)""") 3488 self.assertEqual(c.get_sql_for('recreate'), """RECREATE TABLE EMPLOYEE ( 3489 EMP_NO EMPNO NOT NULL, 3490 FIRST_NAME "FIRSTNAME" NOT NULL, 3491 LAST_NAME "LASTNAME" NOT NULL, 3492 PHONE_EXT VARCHAR(4), 3493 HIRE_DATE TIMESTAMP DEFAULT 'NOW' NOT NULL, 3494 DEPT_NO DEPTNO NOT NULL, 3495 JOB_CODE JOBCODE NOT NULL, 3496 JOB_GRADE JOBGRADE NOT NULL, 3497 JOB_COUNTRY COUNTRYNAME NOT NULL, 3498 SALARY SALARY NOT NULL, 3499 FULL_NAME COMPUTED BY (last_name || ', ' || first_name), 3500 PRIMARY KEY (EMP_NO) 3501)""") 3502 self.assertEqual(c.get_sql_for('drop'), "DROP TABLE EMPLOYEE") 3503 self.assertEqual(c.get_sql_for('comment'), 3504 'COMMENT ON TABLE EMPLOYEE IS NULL') 3505 # Identity colums 3506 if self.con.ods >= fdb.ODS_FB_30: 3507 c = self.con.schema.get_table('T5') 3508 self.assertEqual(c.get_sql_for('create'), """CREATE TABLE T5 ( 3509 ID NUMERIC(10, 0) GENERATED BY DEFAULT AS IDENTITY, 3510 C1 VARCHAR(15), 3511 UQ BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 100), 3512 PRIMARY KEY (ID) 3513)""") 3514 3515 def testView(self): 3516 # User view 3517 c = self.con.schema.get_view('PHONE_LIST') 3518 # common properties 3519 self.assertEqual(c.name, 'PHONE_LIST') 3520 self.assertIsNone(c.description) 3521 self.assertListEqual(c.actions, ['comment', 'create', 3522 'recreate', 'alter', 3523 'create_or_alter', 'drop']) 3524 self.assertFalse(c.issystemobject()) 3525 self.assertEqual(c.get_quoted_name(), 'PHONE_LIST') 3526 self.assertListEqual(c.get_dependents(), []) 3527 d = c.get_dependencies() 3528 if self.con.ods < fdb.ODS_FB_30: 3529 self.assertListEqual([(x.depended_on_name, x.field_name, x.depended_on_type) for x in d], 3530 [('DEPARTMENT', 'DEPT_NO', 0), ('EMPLOYEE', 'DEPT_NO', 0), 3531 ('DEPARTMENT', None, 0), ('EMPLOYEE', None, 0), 3532 ('DEPARTMENT', 'PHONE_NO', 0), ('EMPLOYEE', 'PHONE_EXT', 0), 3533 ('EMPLOYEE', 'LAST_NAME', 0), ('EMPLOYEE', 'EMP_NO', 0), 3534 ('DEPARTMENT', 'LOCATION', 0), ('EMPLOYEE', 'FIRST_NAME', 0)]) 3535 else: 3536 self.assertListEqual([(x.depended_on_name, x.field_name, x.depended_on_type) for x in d], 3537 [('DEPARTMENT', 'DEPT_NO', 0), ('EMPLOYEE', 'DEPT_NO', 0), 3538 ('DEPARTMENT', None, 0), ('EMPLOYEE', None, 0), ('EMPLOYEE', 'EMP_NO', 0), 3539 ('EMPLOYEE', 'FIRST_NAME', 0), ('EMPLOYEE', 'LAST_NAME', 0), 3540 ('EMPLOYEE', 'PHONE_EXT', 0), ('DEPARTMENT', 'LOCATION', 0), 3541 ('DEPARTMENT', 'PHONE_NO', 0)]) 3542 # 3543 if self.con.ods < fdb.ODS_FB_30: 3544 self.assertEqual(c.id, 143) 3545 else: 3546 self.assertEqual(c.id, 132) 3547 self.assertEqual(c.sql, """SELECT 3548 emp_no, first_name, last_name, phone_ext, location, phone_no 3549 FROM employee, department 3550 WHERE employee.dept_no = department.dept_no""") 3551 self.assertEqual(c.dbkey_length, 16) 3552 self.assertEqual(c.format, 1) 3553 if self.con.ods <= fdb.ODS_FB_21: 3554 self.assertEqual(c.security_class, 'SQL$PHONE_LIST') 3555 elif self.con.ods == fdb.ODS_FB_25: 3556 self.assertEqual(c.security_class, 'SQL$8') 3557 elif self.con.ods == fdb.ODS_FB_30: 3558 self.assertEqual(c.security_class, 'SQL$444') 3559 else: 3560 self.assertEqual(c.security_class, 'SQL$483') 3561 self.assertEqual(c.owner_name, 'SYSDBA') 3562 if self.con.ods <= fdb.ODS_FB_20: 3563 self.assertEqual(c.default_class, 'SQL$DEFAULT17') 3564 elif (self.con.ods > fdb.ODS_FB_20) and (self.con.ods < fdb.ODS_FB_30): 3565 self.assertEqual(c.default_class, 'SQL$DEFAULT19') 3566 elif self.con.ods >= fdb.ODS_FB_30: 3567 self.assertEqual(c.default_class, 'SQL$DEFAULT55') 3568 self.assertEqual(c.flags, 1) 3569 self.assertListEqual([x.name for x in c.columns], ['EMP_NO', 'FIRST_NAME', 3570 'LAST_NAME', 'PHONE_EXT', 3571 'LOCATION', 'PHONE_NO']) 3572 self.assertListEqual(c.triggers, []) 3573 # 3574 self.assertEqual(c.get_column('LAST_NAME').name, 'LAST_NAME') 3575 self.assertFalse(c.has_checkoption()) 3576 # 3577 self.assertEqual(c.get_sql_for('create'), 3578 """CREATE VIEW PHONE_LIST (EMP_NO,FIRST_NAME,LAST_NAME,PHONE_EXT,LOCATION,PHONE_NO) 3579 AS 3580 SELECT 3581 emp_no, first_name, last_name, phone_ext, location, phone_no 3582 FROM employee, department 3583 WHERE employee.dept_no = department.dept_no""") 3584 self.assertEqual(c.get_sql_for('recreate'), 3585 """RECREATE VIEW PHONE_LIST (EMP_NO,FIRST_NAME,LAST_NAME,PHONE_EXT,LOCATION,PHONE_NO) 3586 AS 3587 SELECT 3588 emp_no, first_name, last_name, phone_ext, location, phone_no 3589 FROM employee, department 3590 WHERE employee.dept_no = department.dept_no""") 3591 self.assertEqual(c.get_sql_for('drop'), "DROP VIEW PHONE_LIST") 3592 self.assertEqual(c.get_sql_for('alter', query='select * from country'), 3593 "ALTER VIEW PHONE_LIST \n AS\n select * from country") 3594 self.assertEqual(c.get_sql_for('alter', columns='country,currency', 3595 query='select * from country'), 3596 "ALTER VIEW PHONE_LIST (country,currency)\n AS\n select * from country") 3597 self.assertEqual(c.get_sql_for('alter', columns='country,currency', 3598 query='select * from country', check=True), 3599 "ALTER VIEW PHONE_LIST (country,currency)\n AS\n select * from country\n WITH CHECK OPTION") 3600 self.assertEqual(c.get_sql_for('alter', columns=('country', 'currency'), 3601 query='select * from country', check=True), 3602 "ALTER VIEW PHONE_LIST (country,currency)\n AS\n select * from country\n WITH CHECK OPTION") 3603 with self.assertRaises(fdb.ProgrammingError) as cm: 3604 c.get_sql_for('alter', badparam='select * from country') 3605 self.assertTupleEqual(cm.exception.args, 3606 ("Unsupported parameter(s) 'badparam'",)) 3607 with self.assertRaises(fdb.ProgrammingError) as cm: 3608 c.get_sql_for('alter') 3609 self.assertTupleEqual(cm.exception.args, ("Missing required parameter: 'query'.",)) 3610 self.assertEqual(c.get_sql_for('create_or_alter'), 3611 """CREATE OR ALTER VIEW PHONE_LIST (EMP_NO,FIRST_NAME,LAST_NAME,PHONE_EXT,LOCATION,PHONE_NO) 3612 AS 3613 SELECT 3614 emp_no, first_name, last_name, phone_ext, location, phone_no 3615 FROM employee, department 3616 WHERE employee.dept_no = department.dept_no""") 3617 self.assertEqual(c.get_sql_for('comment'), 3618 'COMMENT ON VIEW PHONE_LIST IS NULL') 3619 3620 def testTrigger(self): 3621 # System trigger 3622 c = self.con.schema.get_trigger('RDB$TRIGGER_1') 3623 # common properties 3624 self.assertEqual(c.name, 'RDB$TRIGGER_1') 3625 self.assertIsNone(c.description) 3626 self.assertListEqual(c.actions, ['comment']) 3627 self.assertTrue(c.issystemobject()) 3628 self.assertEqual(c.get_quoted_name(), 'RDB$TRIGGER_1') 3629 self.assertListEqual(c.get_dependents(), []) 3630 self.assertListEqual(c.get_dependencies(), []) 3631 # User trigger 3632 c = self.con.schema.get_trigger('SET_EMP_NO') 3633 # common properties 3634 self.assertEqual(c.name, 'SET_EMP_NO') 3635 self.assertIsNone(c.description) 3636 self.assertListEqual(c.actions, 3637 ['comment', 'create', 'recreate', 'alter', 'create_or_alter', 'drop']) 3638 self.assertFalse(c.issystemobject()) 3639 self.assertEqual(c.get_quoted_name(), 'SET_EMP_NO') 3640 self.assertListEqual(c.get_dependents(), []) 3641 d = c.get_dependencies() 3642 self.assertListEqual([(x.depended_on_name, x.field_name, x.depended_on_type) for x in d], 3643 [('EMPLOYEE', 'EMP_NO', 0), ('EMP_NO_GEN', None, 14)]) 3644 # 3645 self.assertEqual(c.relation.name, 'EMPLOYEE') 3646 self.assertEqual(c.sequence, 0) 3647 self.assertEqual(c.trigger_type, 1) 3648 self.assertEqual(c.source, 3649 "AS\nBEGIN\n if (new.emp_no is null) then\n new.emp_no = gen_id(emp_no_gen, 1);\nEND") 3650 self.assertEqual(c.flags, 1) 3651 # 3652 self.assertTrue(c.isactive()) 3653 self.assertTrue(c.isbefore()) 3654 self.assertFalse(c.isafter()) 3655 self.assertFalse(c.isdbtrigger()) 3656 self.assertTrue(c.isinsert()) 3657 self.assertFalse(c.isupdate()) 3658 self.assertFalse(c.isdelete()) 3659 self.assertEqual(c.get_type_as_string(), 'BEFORE INSERT') 3660 # 3661 if self.con.ods < fdb.ODS_FB_30: 3662 self.assertIsNone(c.valid_blr) 3663 self.assertIsNone(c.engine_name) 3664 self.assertIsNone(c.entrypoint) 3665 else: 3666 self.assertEqual(c.valid_blr, 1) 3667 self.assertIsNone(c.engine_name) 3668 self.assertIsNone(c.entrypoint) 3669 # 3670 self.assertEqual(c.get_sql_for('create'), 3671 """CREATE TRIGGER SET_EMP_NO FOR EMPLOYEE ACTIVE 3672BEFORE INSERT POSITION 0 3673AS 3674BEGIN 3675 if (new.emp_no is null) then 3676 new.emp_no = gen_id(emp_no_gen, 1); 3677END""") 3678 self.assertEqual(c.get_sql_for('recreate'), 3679 """RECREATE TRIGGER SET_EMP_NO FOR EMPLOYEE ACTIVE 3680BEFORE INSERT POSITION 0 3681AS 3682BEGIN 3683 if (new.emp_no is null) then 3684 new.emp_no = gen_id(emp_no_gen, 1); 3685END""") 3686 with self.assertRaises(fdb.ProgrammingError) as cm: 3687 c.get_sql_for('alter') 3688 self.assertTupleEqual(cm.exception.args, 3689 ("Header or body definition required.",)) 3690 with self.assertRaises(fdb.ProgrammingError) as cm: 3691 c.get_sql_for('alter', declare="DECLARE VARIABLE i integer;") 3692 self.assertTupleEqual(cm.exception.args, 3693 ("Header or body definition required.",)) 3694 self.assertEqual(c.get_sql_for('alter', fire_on='AFTER INSERT', 3695 active=False, sequence=0, 3696 declare=' DECLARE VARIABLE i integer;\n DECLARE VARIABLE x integer;', 3697 code=' i = 1;\n x = 2;'), 3698 """ALTER TRIGGER SET_EMP_NO INACTIVE 3699 AFTER INSERT 3700 POSITION 0 3701AS 3702 DECLARE VARIABLE i integer; 3703 DECLARE VARIABLE x integer; 3704BEGIN 3705 i = 1; 3706 x = 2; 3707END""") 3708 self.assertEqual(c.get_sql_for('alter', 3709 declare=['DECLARE VARIABLE i integer;', 3710 'DECLARE VARIABLE x integer;'], 3711 code=['i = 1;', 'x = 2;']), 3712 """ALTER TRIGGER SET_EMP_NO 3713AS 3714 DECLARE VARIABLE i integer; 3715 DECLARE VARIABLE x integer; 3716BEGIN 3717 i = 1; 3718 x = 2; 3719END""") 3720 self.assertEqual(c.get_sql_for('alter', active=False), 3721 "ALTER TRIGGER SET_EMP_NO INACTIVE") 3722 self.assertEqual(c.get_sql_for('alter', sequence=10, 3723 code=('i = 1;', 'x = 2;')), 3724 """ALTER TRIGGER SET_EMP_NO 3725 POSITION 10 3726AS 3727BEGIN 3728 i = 1; 3729 x = 2; 3730END""") 3731 with self.assertRaises(fdb.ProgrammingError) as cm: 3732 c.get_sql_for('alter', fire_on='ON CONNECT') 3733 self.assertTupleEqual(cm.exception.args, 3734 ("Trigger type change is not allowed.",)) 3735 self.assertEqual(c.get_sql_for('create_or_alter'), 3736 """CREATE OR ALTER TRIGGER SET_EMP_NO FOR EMPLOYEE ACTIVE 3737BEFORE INSERT POSITION 0 3738AS 3739BEGIN 3740 if (new.emp_no is null) then 3741 new.emp_no = gen_id(emp_no_gen, 1); 3742END""") 3743 self.assertEqual(c.get_sql_for('drop'), "DROP TRIGGER SET_EMP_NO") 3744 self.assertEqual(c.get_sql_for('comment'), 3745 'COMMENT ON TRIGGER SET_EMP_NO IS NULL') 3746 # Multi-trigger 3747 c = self.con.schema.get_trigger('TR_MULTI') 3748 # 3749 self.assertTrue(c.isinsert()) 3750 self.assertTrue(c.isupdate()) 3751 self.assertTrue(c.isdelete()) 3752 self.assertEqual(c.get_type_as_string(), 3753 'AFTER INSERT OR UPDATE OR DELETE') 3754 # DB trigger 3755 c = self.con.schema.get_trigger('TR_CONNECT') 3756 # 3757 self.assertTrue(c.isdbtrigger()) 3758 self.assertFalse(c.isinsert()) 3759 self.assertFalse(c.isupdate()) 3760 self.assertFalse(c.isdelete()) 3761 self.assertEqual(c.get_type_as_string(), 'ON CONNECT') 3762 3763 def testProcedureParameter(self): 3764 # Input parameter 3765 c = self.con.schema.get_procedure('GET_EMP_PROJ').input_params[0] 3766 # common properties 3767 self.assertEqual(c.name, 'EMP_NO') 3768 self.assertIsNone(c.description) 3769 self.assertListEqual(c.actions, ['comment']) 3770 self.assertFalse(c.issystemobject()) 3771 self.assertEqual(c.get_quoted_name(), 'EMP_NO') 3772 self.assertListEqual(c.get_dependents(), []) 3773 self.assertListEqual(c.get_dependencies(), []) 3774 # 3775 self.assertEqual(c.procedure.name, 'GET_EMP_PROJ') 3776 self.assertEqual(c.sequence, 0) 3777 self.assertEqual(c.domain.name, 'RDB$32') 3778 self.assertEqual(c.datatype, 'SMALLINT') 3779 self.assertEqual(c.type_from, sm.PROCPAR_DATATYPE) 3780 self.assertIsNone(c.default) 3781 self.assertIsNone(c.collation) 3782 if self.con.ods <= fdb.ODS_FB_25: 3783 self.assertEqual(c.mechanism, 0) 3784 elif self.con.ods > fdb.ODS_FB_25: 3785 self.assertEqual(c.mechanism, 0) 3786 self.assertIsNone(c.column) 3787 # 3788 self.assertTrue(c.isinput()) 3789 self.assertTrue(c.isnullable()) 3790 self.assertFalse(c.has_default()) 3791 self.assertEqual(c.get_sql_definition(), 'EMP_NO SMALLINT') 3792 # Output parameter 3793 c = self.con.schema.get_procedure('GET_EMP_PROJ').output_params[0] 3794 # common properties 3795 self.assertEqual(c.name, 'PROJ_ID') 3796 self.assertIsNone(c.description) 3797 self.assertListEqual(c.actions, ['comment']) 3798 self.assertFalse(c.issystemobject()) 3799 self.assertEqual(c.get_quoted_name(), 'PROJ_ID') 3800 self.assertListEqual(c.get_dependents(), []) 3801 self.assertListEqual(c.get_dependencies(), []) 3802 # 3803 self.assertEqual(c.get_sql_for('comment'), 3804 'COMMENT ON PARAMETER GET_EMP_PROJ.PROJ_ID IS NULL') 3805 # 3806 self.assertFalse(c.isinput()) 3807 self.assertEqual(c.get_sql_definition(), 'PROJ_ID CHAR(5)') 3808 def testProcedure(self): 3809 c = self.con.schema.get_procedure('GET_EMP_PROJ') 3810 # common properties 3811 self.assertEqual(c.name, 'GET_EMP_PROJ') 3812 self.assertIsNone(c.description) 3813 self.assertListEqual(c.actions, ['comment', 'create', 3814 'recreate', 'alter', 3815 'create_or_alter', 'drop']) 3816 self.assertFalse(c.issystemobject()) 3817 self.assertEqual(c.get_quoted_name(), 'GET_EMP_PROJ') 3818 self.assertListEqual(c.get_dependents(), []) 3819 d = c.get_dependencies() 3820 self.assertListEqual([(x.depended_on_name, x.field_name, x.depended_on_type) for x in d], 3821 [('EMPLOYEE_PROJECT', 'PROJ_ID', 0), ('EMPLOYEE_PROJECT', 'EMP_NO', 0), 3822 ('EMPLOYEE_PROJECT', None, 0)]) 3823 # 3824 self.assertEqual(c.id, 1) 3825 self.assertEqual(c.source, """BEGIN 3826 FOR SELECT proj_id 3827 FROM employee_project 3828 WHERE emp_no = :emp_no 3829 INTO :proj_id 3830 DO 3831 SUSPEND; 3832END""") 3833 if self.con.ods < fdb.ODS_FB_25: 3834 self.assertEqual(c.security_class, 'SQL$GET_EMP_PROJ') 3835 elif self.con.ods == fdb.ODS_FB_25: 3836 self.assertEqual(c.security_class, 'SQL$20') 3837 elif self.con.ods >= fdb.ODS_FB_30: 3838 self.assertEqual(c.security_class, 'SQL$473') 3839 self.assertEqual(c.owner_name, 'SYSDBA') 3840 self.assertListEqual([x.name for x in c.input_params], ['EMP_NO']) 3841 self.assertListEqual([x.name for x in c.output_params], ['PROJ_ID']) 3842 if self.con.engine_version >= 3.0: 3843 self.assertTrue(c.valid_blr) 3844 self.assertEqual(c.proc_type, 1) 3845 self.assertIsNone(c.engine_name) 3846 self.assertIsNone(c.entrypoint) 3847 self.assertIsNone(c.package) 3848 self.assertIsNone(c.privacy) 3849 else: 3850 self.assertIsNone(c.valid_blr) 3851 self.assertEqual(c.proc_type, 0) 3852 # 3853 self.assertEqual(c.get_param('EMP_NO').name, 'EMP_NO') 3854 self.assertEqual(c.get_param('PROJ_ID').name, 'PROJ_ID') 3855 # 3856 self.assertEqual(c.get_sql_for('create'), 3857 """CREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) 3858RETURNS (PROJ_ID CHAR(5)) 3859AS 3860BEGIN 3861 FOR SELECT proj_id 3862 FROM employee_project 3863 WHERE emp_no = :emp_no 3864 INTO :proj_id 3865 DO 3866 SUSPEND; 3867END""") 3868 if self.version == FB30: 3869 self.assertEqual(c.get_sql_for('create', no_code=True), 3870 """CREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) 3871RETURNS (PROJ_ID CHAR(5)) 3872AS 3873BEGIN 3874 SUSPEND; 3875END""") 3876 else: 3877 self.assertEqual(c.get_sql_for('create', no_code=True), 3878 """CREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) 3879RETURNS (PROJ_ID CHAR(5)) 3880AS 3881BEGIN 3882END""") 3883 self.assertEqual(c.get_sql_for('recreate'), 3884 """RECREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) 3885RETURNS (PROJ_ID CHAR(5)) 3886AS 3887BEGIN 3888 FOR SELECT proj_id 3889 FROM employee_project 3890 WHERE emp_no = :emp_no 3891 INTO :proj_id 3892 DO 3893 SUSPEND; 3894END""") 3895 if self.version == FB30: 3896 self.assertEqual(c.get_sql_for('recreate', no_code=True), 3897 """RECREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) 3898RETURNS (PROJ_ID CHAR(5)) 3899AS 3900BEGIN 3901 SUSPEND; 3902END""") 3903 else: 3904 self.assertEqual(c.get_sql_for('recreate', no_code=True), 3905 """RECREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) 3906RETURNS (PROJ_ID CHAR(5)) 3907AS 3908BEGIN 3909END""") 3910 3911 self.assertEqual(c.get_sql_for('create_or_alter'), 3912 """CREATE OR ALTER PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) 3913RETURNS (PROJ_ID CHAR(5)) 3914AS 3915BEGIN 3916 FOR SELECT proj_id 3917 FROM employee_project 3918 WHERE emp_no = :emp_no 3919 INTO :proj_id 3920 DO 3921 SUSPEND; 3922END""") 3923 if self.version == FB30: 3924 self.assertEqual(c.get_sql_for('create_or_alter', no_code=True), 3925 """CREATE OR ALTER PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) 3926RETURNS (PROJ_ID CHAR(5)) 3927AS 3928BEGIN 3929 SUSPEND; 3930END""") 3931 else: 3932 self.assertEqual(c.get_sql_for('create_or_alter', no_code=True), 3933 """CREATE OR ALTER PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT) 3934RETURNS (PROJ_ID CHAR(5)) 3935AS 3936BEGIN 3937END""") 3938 self.assertEqual(c.get_sql_for('drop'), "DROP PROCEDURE GET_EMP_PROJ") 3939 self.assertEqual(c.get_sql_for('alter', code=" /* PASS */"), 3940 """ALTER PROCEDURE GET_EMP_PROJ 3941AS 3942BEGIN 3943 /* PASS */ 3944END""") 3945 with self.assertRaises(fdb.ProgrammingError) as cm: 3946 c.get_sql_for('alter', declare="DECLARE VARIABLE i integer;") 3947 self.assertTupleEqual(cm.exception.args, 3948 ("Missing required parameter: 'code'.",)) 3949 self.assertEqual(c.get_sql_for('alter', code=''), 3950 """ALTER PROCEDURE GET_EMP_PROJ 3951AS 3952BEGIN 3953END""") 3954 self.assertEqual(c.get_sql_for('alter', input="IN1 integer", code=''), 3955 """ALTER PROCEDURE GET_EMP_PROJ (IN1 integer) 3956AS 3957BEGIN 3958END""") 3959 self.assertEqual(c.get_sql_for('alter', output="OUT1 integer", code=''), 3960 """ALTER PROCEDURE GET_EMP_PROJ 3961RETURNS (OUT1 integer) 3962AS 3963BEGIN 3964END""") 3965 self.assertEqual(c.get_sql_for('alter', input="IN1 integer", 3966 output="OUT1 integer", code=''), 3967 """ALTER PROCEDURE GET_EMP_PROJ (IN1 integer) 3968RETURNS (OUT1 integer) 3969AS 3970BEGIN 3971END""") 3972 self.assertEqual(c.get_sql_for('alter', 3973 input=["IN1 integer", "IN2 VARCHAR(10)"], 3974 code=''), 3975 """ALTER PROCEDURE GET_EMP_PROJ ( 3976 IN1 integer, 3977 IN2 VARCHAR(10) 3978) 3979AS 3980BEGIN 3981END""") 3982 self.assertEqual(c.get_sql_for('alter', 3983 output=["OUT1 integer", "OUT2 VARCHAR(10)"], 3984 code=''), 3985 """ALTER PROCEDURE GET_EMP_PROJ 3986RETURNS ( 3987 OUT1 integer, 3988 OUT2 VARCHAR(10) 3989) 3990AS 3991BEGIN 3992END""") 3993 self.assertEqual(c.get_sql_for('alter', 3994 input=["IN1 integer", "IN2 VARCHAR(10)"], 3995 output=["OUT1 integer", "OUT2 VARCHAR(10)"], 3996 code=''), 3997 """ALTER PROCEDURE GET_EMP_PROJ ( 3998 IN1 integer, 3999 IN2 VARCHAR(10) 4000) 4001RETURNS ( 4002 OUT1 integer, 4003 OUT2 VARCHAR(10) 4004) 4005AS 4006BEGIN 4007END""") 4008 self.assertEqual(c.get_sql_for('alter', code=" -- line 1;\n -- line 2;"), 4009 """ALTER PROCEDURE GET_EMP_PROJ 4010AS 4011BEGIN 4012 -- line 1; 4013 -- line 2; 4014END""") 4015 self.assertEqual(c.get_sql_for('alter', code=["-- line 1;", "-- line 2;"]), 4016 """ALTER PROCEDURE GET_EMP_PROJ 4017AS 4018BEGIN 4019 -- line 1; 4020 -- line 2; 4021END""") 4022 self.assertEqual(c.get_sql_for('alter', code=" /* PASS */", 4023 declare=" -- line 1;\n -- line 2;"), 4024 """ALTER PROCEDURE GET_EMP_PROJ 4025AS 4026 -- line 1; 4027 -- line 2; 4028BEGIN 4029 /* PASS */ 4030END""") 4031 self.assertEqual(c.get_sql_for('alter', code=" /* PASS */", 4032 declare=["-- line 1;", "-- line 2;"]), 4033 """ALTER PROCEDURE GET_EMP_PROJ 4034AS 4035 -- line 1; 4036 -- line 2; 4037BEGIN 4038 /* PASS */ 4039END""") 4040 self.assertEqual(c.get_sql_for('comment'), 4041 'COMMENT ON PROCEDURE GET_EMP_PROJ IS NULL') 4042 def testRole(self): 4043 c = self.con.schema.get_role('TEST_ROLE') 4044 # common properties 4045 self.assertEqual(c.name, 'TEST_ROLE') 4046 self.assertIsNone(c.description) 4047 self.assertListEqual(c.actions, ['comment', 'create', 'drop']) 4048 self.assertFalse(c.issystemobject()) 4049 self.assertEqual(c.get_quoted_name(), 'TEST_ROLE') 4050 self.assertListEqual(c.get_dependents(), []) 4051 self.assertListEqual(c.get_dependencies(), []) 4052 # 4053 self.assertEqual(c.owner_name, 'SYSDBA') 4054 # 4055 self.assertEqual(c.get_sql_for('create'), "CREATE ROLE TEST_ROLE") 4056 self.assertEqual(c.get_sql_for('drop'), "DROP ROLE TEST_ROLE") 4057 self.assertEqual(c.get_sql_for('comment'), 4058 'COMMENT ON ROLE TEST_ROLE IS NULL') 4059 def _mockFunction(self, name): 4060 f = None 4061 if name == 'STRLEN': 4062 f = sm.Function(self.con.schema, 4063 {'RDB$ENTRYPOINT': 'IB_UDF_strlen ', 4064 'RDB$SYSTEM_FLAG': 0, 'RDB$RETURN_ARGUMENT': 0, 4065 'RDB$MODULE_NAME': 'ib_udf', 'RDB$FUNCTION_TYPE': None, 4066 'RDB$DESCRIPTION': None, 4067 'RDB$FUNCTION_NAME': 'STRLEN '}) 4068 f._load_arguments( 4069 [{'RDB$FIELD_PRECISION': 0, 'RDB$FIELD_LENGTH': 4, 4070 'RDB$FIELD_SCALE': 0, 'RDB$FIELD_SUB_TYPE': 0, 4071 'RDB$FIELD_TYPE': 8, 'RDB$MECHANISM': 0, 4072 'RDB$CHARACTER_SET_ID': None, 'RDB$CHARACTER_LENGTH': None, 4073 'RDB$FUNCTION_NAME': 'STRLEN ', 4074 'RDB$ARGUMENT_POSITION': 0}, 4075 {'RDB$FIELD_PRECISION': None, 'RDB$FIELD_LENGTH': 32767, 4076 'RDB$FIELD_SCALE': 0, 'RDB$FIELD_SUB_TYPE': 0, 4077 'RDB$FIELD_TYPE': 40, 'RDB$MECHANISM': 1, 4078 'RDB$CHARACTER_SET_ID': 0, 'RDB$CHARACTER_LENGTH': 32767, 4079 'RDB$FUNCTION_NAME': 'STRLEN ', 4080 'RDB$ARGUMENT_POSITION': 1}]) 4081 elif name == 'STRING2BLOB': 4082 f = sm.Function(self.con.schema, 4083 {'RDB$ENTRYPOINT': 'string2blob ', 4084 'RDB$SYSTEM_FLAG': 0, 'RDB$RETURN_ARGUMENT': 2, 4085 'RDB$MODULE_NAME': 'fbudf', 'RDB$FUNCTION_TYPE': None, 4086 'RDB$DESCRIPTION': None, 4087 'RDB$FUNCTION_NAME': 'STRING2BLOB '}) 4088 f._load_arguments( 4089 [{'RDB$FIELD_PRECISION': None, 'RDB$FIELD_LENGTH': 300, 4090 'RDB$FIELD_SCALE': 0, 'RDB$FIELD_SUB_TYPE': 0, 4091 'RDB$FIELD_TYPE': 37, 'RDB$MECHANISM': 2, 4092 'RDB$CHARACTER_SET_ID': 0, 'RDB$CHARACTER_LENGTH': 300, 4093 'RDB$FUNCTION_NAME': 'STRING2BLOB ', 4094 'RDB$ARGUMENT_POSITION': 1}, 4095 {'RDB$FIELD_PRECISION': None, 'RDB$FIELD_LENGTH': 8, 4096 'RDB$FIELD_SCALE': 0, 'RDB$FIELD_SUB_TYPE': 0, 4097 'RDB$FIELD_TYPE': 261, 'RDB$MECHANISM': 3, 4098 'RDB$CHARACTER_SET_ID': None, 'RDB$CHARACTER_LENGTH': None, 4099 'RDB$FUNCTION_NAME': 'STRING2BLOB ', 4100 'RDB$ARGUMENT_POSITION': 2}]) 4101 elif name == 'LTRIM': 4102 f = sm.Function(self.con.schema, 4103 {'RDB$ENTRYPOINT': 'IB_UDF_ltrim ', 4104 'RDB$SYSTEM_FLAG': 0, 'RDB$RETURN_ARGUMENT': 0, 4105 'RDB$MODULE_NAME': 'ib_udf', 'RDB$FUNCTION_TYPE': None, 4106 'RDB$DESCRIPTION': None, 4107 'RDB$FUNCTION_NAME': 'LTRIM '}) 4108 f._load_arguments( 4109 [{'RDB$FIELD_PRECISION': None, 'RDB$FIELD_LENGTH': 255, 4110 'RDB$FIELD_SCALE': 0, 'RDB$FIELD_SUB_TYPE': 0, 4111 'RDB$FIELD_TYPE': 40, 'RDB$MECHANISM': -1, 4112 'RDB$CHARACTER_SET_ID': 0, 'RDB$CHARACTER_LENGTH': 255, 4113 'RDB$FUNCTION_NAME': 'LTRIM ', 4114 'RDB$ARGUMENT_POSITION': 0}, 4115 {'RDB$FIELD_PRECISION': None, 'RDB$FIELD_LENGTH': 255, 4116 'RDB$FIELD_SCALE': 0, 'RDB$FIELD_SUB_TYPE': 0, 4117 'RDB$FIELD_TYPE': 40, 'RDB$MECHANISM': 1, 4118 'RDB$CHARACTER_SET_ID': 0, 'RDB$CHARACTER_LENGTH': 255, 4119 'RDB$FUNCTION_NAME': 'LTRIM ', 4120 'RDB$ARGUMENT_POSITION': 1}]) 4121 elif name == 'I64NVL': 4122 f = sm.Function(self.con.schema, 4123 {'RDB$ENTRYPOINT': 'idNvl ', 4124 'RDB$SYSTEM_FLAG': 0, 'RDB$RETURN_ARGUMENT': 0, 4125 'RDB$MODULE_NAME': 'fbudf', 'RDB$FUNCTION_TYPE': None, 4126 'RDB$DESCRIPTION': None, 4127 'RDB$FUNCTION_NAME': 'I64NVL '}) 4128 f._load_arguments( 4129 [{'RDB$FIELD_PRECISION': 18, 'RDB$FIELD_LENGTH': 8, 4130 'RDB$FIELD_SCALE': 0, 'RDB$FIELD_SUB_TYPE': 1, 4131 'RDB$FIELD_TYPE': 16, 'RDB$MECHANISM': 2, 4132 'RDB$CHARACTER_SET_ID': None, 'RDB$CHARACTER_LENGTH': None, 4133 'RDB$FUNCTION_NAME': 'I64NVL ', 4134 'RDB$ARGUMENT_POSITION': 0}, 4135 {'RDB$FIELD_PRECISION': 18, 'RDB$FIELD_LENGTH': 8, 4136 'RDB$FIELD_SCALE': 0, 'RDB$FIELD_SUB_TYPE': 1, 4137 'RDB$FIELD_TYPE': 16, 'RDB$MECHANISM': 2, 4138 'RDB$CHARACTER_SET_ID': None, 'RDB$CHARACTER_LENGTH': None, 4139 'RDB$FUNCTION_NAME': 'I64NVL ', 4140 'RDB$ARGUMENT_POSITION': 1}, 4141 {'RDB$FIELD_PRECISION': 18, 'RDB$FIELD_LENGTH': 8, 4142 'RDB$FIELD_SCALE': 0, 'RDB$FIELD_SUB_TYPE': 1, 4143 'RDB$FIELD_TYPE': 16, 'RDB$MECHANISM': 2, 4144 'RDB$CHARACTER_SET_ID': None, 'RDB$CHARACTER_LENGTH': None, 4145 'RDB$FUNCTION_NAME': 'I64NVL ', 4146 'RDB$ARGUMENT_POSITION': 2}]) 4147 if f: 4148 return f 4149 else: 4150 raise Exception("Udefined function for mock.") 4151 def testFunctionArgument(self): 4152 f = self._mockFunction('STRLEN') 4153 c = f.arguments[0] 4154 self.assertEqual(len(f.arguments), 1) 4155 # common properties 4156 self.assertEqual(c.name, 'STRLEN_1') 4157 self.assertIsNone(c.description) 4158 self.assertListEqual(c.actions, []) 4159 self.assertFalse(c.issystemobject()) 4160 self.assertEqual(c.get_quoted_name(), 'STRLEN_1') 4161 self.assertListEqual(c.get_dependents(), []) 4162 self.assertListEqual(c.get_dependencies(), []) 4163 # 4164 self.assertEqual(c.function.name, 'STRLEN') 4165 self.assertEqual(c.position, 1) 4166 self.assertEqual(c.mechanism, 1) 4167 self.assertEqual(c.field_type, 40) 4168 self.assertEqual(c.length, 32767) 4169 self.assertEqual(c.scale, 0) 4170 self.assertIsNone(c.precision) 4171 self.assertEqual(c.sub_type, 0) 4172 self.assertEqual(c.character_length, 32767) 4173 self.assertEqual(c.character_set.name, 'NONE') 4174 self.assertEqual(c.datatype, 'CSTRING(32767)') 4175 # 4176 self.assertFalse(c.isbyvalue()) 4177 self.assertTrue(c.isbyreference()) 4178 self.assertFalse(c.isbydescriptor()) 4179 self.assertFalse(c.iswithnull()) 4180 self.assertFalse(c.isfreeit()) 4181 self.assertFalse(c.isreturning()) 4182 self.assertEqual(c.get_sql_definition(), 'CSTRING(32767)') 4183 # 4184 c = f.returns 4185 # 4186 self.assertEqual(c.position, 0) 4187 self.assertEqual(c.mechanism, 0) 4188 self.assertEqual(c.field_type, 8) 4189 self.assertEqual(c.length, 4) 4190 self.assertEqual(c.scale, 0) 4191 self.assertEqual(c.precision, 0) 4192 self.assertEqual(c.sub_type, 0) 4193 self.assertIsNone(c.character_length) 4194 self.assertIsNone(c.character_set) 4195 self.assertEqual(c.datatype, 'INTEGER') 4196 # 4197 self.assertTrue(c.isbyvalue()) 4198 self.assertFalse(c.isbyreference()) 4199 self.assertFalse(c.isbydescriptor()) 4200 self.assertFalse(c.iswithnull()) 4201 self.assertFalse(c.isfreeit()) 4202 self.assertTrue(c.isreturning()) 4203 self.assertEqual(c.get_sql_definition(), 'INTEGER BY VALUE') 4204 # 4205 f = self._mockFunction('STRING2BLOB') 4206 self.assertEqual(len(f.arguments), 2) 4207 c = f.arguments[0] 4208 self.assertEqual(c.function.name, 'STRING2BLOB') 4209 self.assertEqual(c.position, 1) 4210 self.assertEqual(c.mechanism, 2) 4211 self.assertEqual(c.field_type, 37) 4212 self.assertEqual(c.length, 300) 4213 self.assertEqual(c.scale, 0) 4214 self.assertIsNone(c.precision) 4215 self.assertEqual(c.sub_type, 0) 4216 self.assertEqual(c.character_length, 300) 4217 self.assertEqual(c.character_set.name, 'NONE') 4218 self.assertEqual(c.datatype, 'VARCHAR(300)') 4219 # 4220 self.assertFalse(c.isbyvalue()) 4221 self.assertFalse(c.isbyreference()) 4222 self.assertTrue(c.isbydescriptor()) 4223 self.assertFalse(c.iswithnull()) 4224 self.assertFalse(c.isfreeit()) 4225 self.assertFalse(c.isreturning()) 4226 self.assertEqual(c.get_sql_definition(), 'VARCHAR(300) BY DESCRIPTOR') 4227 # 4228 c = f.arguments[1] 4229 self.assertIs(f.arguments[1], f.returns) 4230 self.assertEqual(c.function.name, 'STRING2BLOB') 4231 self.assertEqual(c.position, 2) 4232 self.assertEqual(c.mechanism, 3) 4233 self.assertEqual(c.field_type, 261) 4234 self.assertEqual(c.length, 8) 4235 self.assertEqual(c.scale, 0) 4236 self.assertIsNone(c.precision) 4237 self.assertEqual(c.sub_type, 0) 4238 self.assertIsNone(c.character_length) 4239 self.assertIsNone(c.character_set) 4240 self.assertEqual(c.datatype, 'BLOB') 4241 # 4242 self.assertFalse(c.isbyvalue()) 4243 self.assertFalse(c.isbyreference()) 4244 self.assertFalse(c.isbydescriptor()) 4245 self.assertTrue(c.isbydescriptor(any=True)) 4246 self.assertFalse(c.iswithnull()) 4247 self.assertFalse(c.isfreeit()) 4248 self.assertTrue(c.isreturning()) 4249 self.assertEqual(c.get_sql_definition(), 'BLOB') 4250 # 4251 f = self._mockFunction('LTRIM') 4252 self.assertEqual(len(f.arguments), 1) 4253 c = f.arguments[0] 4254 self.assertEqual(c.function.name, 'LTRIM') 4255 self.assertEqual(c.position, 1) 4256 self.assertEqual(c.mechanism, 1) 4257 self.assertEqual(c.field_type, 40) 4258 self.assertEqual(c.length, 255) 4259 self.assertEqual(c.scale, 0) 4260 self.assertIsNone(c.precision) 4261 self.assertEqual(c.sub_type, 0) 4262 self.assertEqual(c.character_length, 255) 4263 self.assertEqual(c.character_set.name, 'NONE') 4264 self.assertEqual(c.datatype, 'CSTRING(255)') 4265 # 4266 self.assertFalse(c.isbyvalue()) 4267 self.assertTrue(c.isbyreference()) 4268 self.assertFalse(c.isbydescriptor()) 4269 self.assertFalse(c.iswithnull()) 4270 self.assertFalse(c.isfreeit()) 4271 self.assertFalse(c.isreturning()) 4272 self.assertEqual(c.get_sql_definition(), 'CSTRING(255)') 4273 # 4274 c = f.returns 4275 self.assertEqual(c.function.name, 'LTRIM') 4276 self.assertEqual(c.position, 0) 4277 self.assertEqual(c.mechanism, 1) 4278 self.assertEqual(c.field_type, 40) 4279 self.assertEqual(c.length, 255) 4280 self.assertEqual(c.scale, 0) 4281 self.assertIsNone(c.precision) 4282 self.assertEqual(c.sub_type, 0) 4283 self.assertEqual(c.character_length, 255) 4284 self.assertEqual(c.character_set.name, 'NONE') 4285 self.assertEqual(c.datatype, 'CSTRING(255)') 4286 # 4287 self.assertFalse(c.isbyvalue()) 4288 self.assertTrue(c.isbyreference()) 4289 self.assertFalse(c.isbydescriptor()) 4290 self.assertFalse(c.isbydescriptor(any=True)) 4291 self.assertFalse(c.iswithnull()) 4292 self.assertTrue(c.isfreeit()) 4293 self.assertTrue(c.isreturning()) 4294 self.assertEqual(c.get_sql_definition(), 'CSTRING(255)') 4295 # 4296 f = self._mockFunction('I64NVL') 4297 self.assertEqual(len(f.arguments), 2) 4298 for a in f.arguments: 4299 self.assertEqual(a.datatype, 'NUMERIC(18, 0)') 4300 self.assertTrue(a.isbydescriptor()) 4301 self.assertEqual(a.get_sql_definition(), 4302 'NUMERIC(18, 0) BY DESCRIPTOR') 4303 self.assertEqual(f.returns.datatype, 'NUMERIC(18, 0)') 4304 self.assertTrue(f.returns.isbydescriptor()) 4305 self.assertEqual(f.returns.get_sql_definition(), 4306 'NUMERIC(18, 0) BY DESCRIPTOR') 4307 def testFunction(self): 4308 c = self._mockFunction('STRLEN') 4309 self.assertEqual(len(c.arguments), 1) 4310 # common properties 4311 self.assertEqual(c.name, 'STRLEN') 4312 self.assertIsNone(c.description) 4313 self.assertIsNone(c.package) 4314 self.assertIsNone(c.engine_mame) 4315 self.assertIsNone(c.private_flag) 4316 self.assertIsNone(c.source) 4317 self.assertIsNone(c.id) 4318 self.assertIsNone(c.valid_blr) 4319 self.assertIsNone(c.security_class) 4320 self.assertIsNone(c.owner_name) 4321 self.assertIsNone(c.legacy_flag) 4322 self.assertIsNone(c.deterministic_flag) 4323 self.assertListEqual(c.actions, ['comment', 'declare', 'drop']) 4324 self.assertFalse(c.issystemobject()) 4325 self.assertEqual(c.get_quoted_name(), 'STRLEN') 4326 self.assertListEqual(c.get_dependents(), []) 4327 self.assertListEqual(c.get_dependencies(), []) 4328 self.assertFalse(c.ispackaged()) 4329 # 4330 self.assertEqual(c.module_name, 'ib_udf') 4331 self.assertEqual(c.entrypoint, 'IB_UDF_strlen') 4332 self.assertEqual(c.returns.name, 'STRLEN_0') 4333 self.assertListEqual([a.name for a in c.arguments], ['STRLEN_1']) 4334 # 4335 self.assertTrue(c.has_arguments()) 4336 self.assertTrue(c.has_return()) 4337 self.assertFalse(c.has_return_argument()) 4338 # 4339 self.assertEqual(c.get_sql_for('drop'), "DROP EXTERNAL FUNCTION STRLEN") 4340 with self.assertRaises(fdb.ProgrammingError) as cm: 4341 c.get_sql_for('drop', badparam='') 4342 self.assertTupleEqual(cm.exception.args, 4343 ("Unsupported parameter(s) 'badparam'",)) 4344 self.assertEqual(c.get_sql_for('declare'), 4345 """DECLARE EXTERNAL FUNCTION STRLEN 4346 CSTRING(32767) 4347RETURNS INTEGER BY VALUE 4348ENTRY_POINT 'IB_UDF_strlen' 4349MODULE_NAME 'ib_udf'""") 4350 with self.assertRaises(fdb.ProgrammingError) as cm: 4351 c.get_sql_for('declare', badparam='') 4352 self.assertTupleEqual(cm.exception.args, 4353 ("Unsupported parameter(s) 'badparam'",)) 4354 self.assertEqual(c.get_sql_for('comment'), 4355 'COMMENT ON EXTERNAL FUNCTION STRLEN IS NULL') 4356 # 4357 c = self._mockFunction('STRING2BLOB') 4358 self.assertEqual(len(c.arguments), 2) 4359 # 4360 self.assertTrue(c.has_arguments()) 4361 self.assertTrue(c.has_return()) 4362 self.assertTrue(c.has_return_argument()) 4363 # 4364 self.assertEqual(c.get_sql_for('declare'), 4365 """DECLARE EXTERNAL FUNCTION STRING2BLOB 4366 VARCHAR(300) BY DESCRIPTOR, 4367 BLOB 4368RETURNS PARAMETER 2 4369ENTRY_POINT 'string2blob' 4370MODULE_NAME 'fbudf'""") 4371 # 4372 c = self._mockFunction('LTRIM') 4373 self.assertEqual(len(c.arguments), 1) 4374 # 4375 self.assertTrue(c.has_arguments()) 4376 self.assertTrue(c.has_return()) 4377 self.assertFalse(c.has_return_argument()) 4378 # 4379 self.assertEqual(c.get_sql_for('declare'), 4380 """DECLARE EXTERNAL FUNCTION LTRIM 4381 CSTRING(255) 4382RETURNS CSTRING(255) FREE_IT 4383ENTRY_POINT 'IB_UDF_ltrim' 4384MODULE_NAME 'ib_udf'""") 4385 # 4386 c = self._mockFunction('I64NVL') 4387 self.assertEqual(len(c.arguments), 2) 4388 # 4389 self.assertTrue(c.has_arguments()) 4390 self.assertTrue(c.has_return()) 4391 self.assertFalse(c.has_return_argument()) 4392 # 4393 self.assertEqual(c.get_sql_for('declare'), 4394 """DECLARE EXTERNAL FUNCTION I64NVL 4395 NUMERIC(18, 0) BY DESCRIPTOR, 4396 NUMERIC(18, 0) BY DESCRIPTOR 4397RETURNS NUMERIC(18, 0) BY DESCRIPTOR 4398ENTRY_POINT 'idNvl' 4399MODULE_NAME 'fbudf'""") 4400 # 4401 # Internal PSQL functions (Firebird 3.0) 4402 if self.con.ods >= fdb.ODS_FB_30: 4403 c = self.con.schema.get_function('F2') 4404 # common properties 4405 self.assertEqual(c.name, 'F2') 4406 self.assertIsNone(c.description) 4407 self.assertIsNone(c.package) 4408 self.assertIsNone(c.engine_mame) 4409 self.assertIsNone(c.private_flag) 4410 self.assertEqual(c.source, 'BEGIN\n RETURN X+1;\nEND') 4411 self.assertEqual(c.id, 3) 4412 self.assertTrue(c.valid_blr) 4413 self.assertEqual(c.security_class, 'SQL$588') 4414 self.assertEqual(c.owner_name, 'SYSDBA') 4415 self.assertEqual(c.legacy_flag, 0) 4416 self.assertEqual(c.deterministic_flag, 0) 4417 # 4418 self.assertListEqual(c.actions, ['create', 'recreate', 'alter', 'create_or_alter', 'drop']) 4419 self.assertFalse(c.issystemobject()) 4420 self.assertEqual(c.get_quoted_name(), 'F2') 4421 self.assertListEqual(c.get_dependents(), []) 4422 self.assertListEqual(c.get_dependencies(), []) 4423 # 4424 self.assertIsNone(c.module_name) 4425 self.assertIsNone(c.entrypoint) 4426 self.assertEqual(c.returns.name, 'F2_0') 4427 self.assertListEqual([a.name for a in c.arguments], ['X']) 4428 # 4429 self.assertTrue(c.has_arguments()) 4430 self.assertTrue(c.has_return()) 4431 self.assertFalse(c.has_return_argument()) 4432 self.assertFalse(c.ispackaged()) 4433 # 4434 self.assertEqual(c.get_sql_for('drop'), "DROP FUNCTION F2") 4435 self.assertEqual(c.get_sql_for('create'), 4436 """CREATE FUNCTION F2 (X INTEGER) 4437RETURNS INTEGER 4438AS 4439BEGIN 4440 RETURN X+1; 4441END""") 4442 self.assertEqual(c.get_sql_for('create', no_code=True), 4443 """CREATE FUNCTION F2 (X INTEGER) 4444RETURNS INTEGER 4445AS 4446BEGIN 4447END""") 4448 self.assertEqual(c.get_sql_for('recreate'), 4449 """RECREATE FUNCTION F2 (X INTEGER) 4450RETURNS INTEGER 4451AS 4452BEGIN 4453 RETURN X+1; 4454END""") 4455 4456 self.assertEqual(c.get_sql_for('create_or_alter'), 4457 """CREATE OR ALTER FUNCTION F2 (X INTEGER) 4458RETURNS INTEGER 4459AS 4460BEGIN 4461 RETURN X+1; 4462END""") 4463 with self.assertRaises(fdb.ProgrammingError) as cm: 4464 c.get_sql_for('alter', declare="DECLARE VARIABLE i integer;", code='') 4465 self.assertTupleEqual(cm.exception.args, 4466 ("Missing required parameter: 'returns'.",)) 4467 with self.assertRaises(fdb.ProgrammingError) as cm: 4468 c.get_sql_for('alter', declare="DECLARE VARIABLE i integer;", returns='INTEGER') 4469 self.assertTupleEqual(cm.exception.args, 4470 ("Missing required parameter: 'code'.",)) 4471 self.assertEqual(c.get_sql_for('alter', returns='INTEGER', code=''), 4472 """ALTER FUNCTION F2 4473RETURNS INTEGER 4474AS 4475BEGIN 4476END""") 4477 self.assertEqual(c.get_sql_for('alter', arguments="IN1 integer", returns='INTEGER', code=''), 4478 """ALTER FUNCTION F2 (IN1 integer) 4479RETURNS INTEGER 4480AS 4481BEGIN 4482END""") 4483 self.assertEqual(c.get_sql_for('alter', returns='INTEGER', 4484 arguments=["IN1 integer", "IN2 VARCHAR(10)"], 4485 code=''), 4486 """ALTER FUNCTION F2 ( 4487 IN1 integer, 4488 IN2 VARCHAR(10) 4489) 4490RETURNS INTEGER 4491AS 4492BEGIN 4493END""") 4494 # 4495 c = self.con.schema.get_function('FX') 4496 self.assertEqual(c.get_sql_for('create'),"""CREATE FUNCTION FX ( 4497 F TYPE OF "FIRSTNAME", 4498 L TYPE OF COLUMN CUSTOMER.CONTACT_LAST 4499) 4500RETURNS VARCHAR(35) 4501AS 4502BEGIN 4503 RETURN L || \', \' || F; 4504END""") 4505 #"""CREATE FUNCTION FX ( 4506 #L TYPE OF COLUMN CUSTOMER.CONTACT_LAST 4507#) 4508#RETURNS VARCHAR(35) 4509#AS 4510#BEGIN 4511 #RETURN L || ', ' || F; 4512#END""") 4513 # 4514 c = self.con.schema.get_function('F1') 4515 self.assertEqual(c.name, 'F1') 4516 self.assertIsNotNone(c.package) 4517 self.assertIsInstance(c.package, sm.Package) 4518 self.assertListEqual(c.actions, []) 4519 self.assertTrue(c.private_flag) 4520 self.assertTrue(c.ispackaged()) 4521 4522 def testDatabaseFile(self): 4523 # We have to use mock 4524 c = sm.DatabaseFile(self.con.schema, {'RDB$FILE_LENGTH': 1000, 4525 'RDB$FILE_NAME': '/path/dbfile.f02', 4526 'RDB$FILE_START': 500, 4527 'RDB$FILE_SEQUENCE': 1}) 4528 # common properties 4529 self.assertEqual(c.name, 'FILE_1') 4530 self.assertIsNone(c.description) 4531 self.assertListEqual(c.actions, []) 4532 self.assertTrue(c.issystemobject()) 4533 self.assertEqual(c.get_quoted_name(), 'FILE_1') 4534 self.assertListEqual(c.get_dependents(), []) 4535 self.assertListEqual(c.get_dependencies(), []) 4536 # 4537 self.assertEqual(c.filename, '/path/dbfile.f02') 4538 self.assertEqual(c.sequence, 1) 4539 self.assertEqual(c.start, 500) 4540 self.assertEqual(c.length, 1000) 4541 # 4542 def testShadow(self): 4543 # We have to use mocks 4544 c = sm.Shadow(self.con.schema, {'RDB$FILE_FLAGS': 1, 4545 'RDB$SHADOW_NUMBER': 3}) 4546 files = [] 4547 files.append(sm.DatabaseFile(self.con.schema, {'RDB$FILE_LENGTH': 500, 4548 'RDB$FILE_NAME': '/path/shadow.sf1', 4549 'RDB$FILE_START': 0, 4550 'RDB$FILE_SEQUENCE': 0})) 4551 files.append(sm.DatabaseFile(self.con.schema, {'RDB$FILE_LENGTH': 500, 4552 'RDB$FILE_NAME': '/path/shadow.sf2', 4553 'RDB$FILE_START': 1000, 4554 'RDB$FILE_SEQUENCE': 1})) 4555 files.append(sm.DatabaseFile(self.con.schema, {'RDB$FILE_LENGTH': 0, 4556 'RDB$FILE_NAME': '/path/shadow.sf3', 4557 'RDB$FILE_START': 1500, 4558 'RDB$FILE_SEQUENCE': 2})) 4559 c.__dict__['_Shadow__files'] = files 4560 # common properties 4561 self.assertEqual(c.name, 'SHADOW_3') 4562 self.assertIsNone(c.description) 4563 self.assertListEqual(c.actions, ['create', 'drop']) 4564 self.assertFalse(c.issystemobject()) 4565 self.assertEqual(c.get_quoted_name(), 'SHADOW_3') 4566 self.assertListEqual(c.get_dependents(), []) 4567 self.assertListEqual(c.get_dependencies(), []) 4568 # 4569 self.assertEqual(c.id, 3) 4570 self.assertEqual(c.flags, 1) 4571 self.assertListEqual([(f.name, f.filename, f.start, f.length) for f in c.files], 4572 [('FILE_0', '/path/shadow.sf1', 0, 500), 4573 ('FILE_1', '/path/shadow.sf2', 1000, 500), 4574 ('FILE_2', '/path/shadow.sf3', 1500, 0)]) 4575 # 4576 self.assertFalse(c.isconditional()) 4577 self.assertFalse(c.isinactive()) 4578 self.assertFalse(c.ismanual()) 4579 # 4580 self.assertEqual(c.get_sql_for('create'), 4581 """CREATE SHADOW 3 AUTO '/path/shadow.sf1' LENGTH 500 4582 FILE '/path/shadow.sf2' STARTING AT 1000 LENGTH 500 4583 FILE '/path/shadow.sf3' STARTING AT 1500""") 4584 self.assertEqual(c.get_sql_for('drop'), "DROP SHADOW 3") 4585 self.assertEqual(c.get_sql_for('drop', preserve=True), "DROP SHADOW 3 PRESERVE FILE") 4586 def testPrivilegeBasic(self): 4587 p = self.con.schema.get_procedure('ALL_LANGS') 4588 # 4589 self.assertIsInstance(p.privileges, list) 4590 self.assertEqual(len(p.privileges), 2) 4591 c = p.privileges[0] 4592 # common properties 4593 self.assertIsNone(c.name) 4594 self.assertIsNone(c.description) 4595 self.assertListEqual(c.actions, ['grant', 'revoke']) 4596 self.assertTrue(c.issystemobject()) 4597 self.assertIsNone(c.get_quoted_name()) 4598 self.assertListEqual(c.get_dependents(), []) 4599 self.assertListEqual(c.get_dependencies(), []) 4600 # 4601 self.assertIsInstance(c.user, fdb.services.User) 4602 self.assertIn(c.user.name, ['SYSDBA', 'PUBLIC']) 4603 self.assertIsInstance(c.grantor, fdb.services.User) 4604 self.assertEqual(c.grantor.name, 'SYSDBA') 4605 self.assertEqual(c.privilege, 'X') 4606 self.assertIsInstance(c.subject, sm.Procedure) 4607 self.assertEqual(c.subject.name, 'ALL_LANGS') 4608 self.assertIn(c.user_name, ['SYSDBA', 'PUBLIC']) 4609 self.assertEqual(c.user_type, self.con.schema.enum_object_type_codes['USER']) 4610 self.assertEqual(c.grantor_name, 'SYSDBA') 4611 self.assertEqual(c.subject_name, 'ALL_LANGS') 4612 self.assertEqual(c.subject_type, self.con.schema.enum_object_type_codes['PROCEDURE']) 4613 self.assertIsNone(c.field_name) 4614 # 4615 self.assertFalse(c.has_grant()) 4616 self.assertFalse(c.isselect()) 4617 self.assertFalse(c.isinsert()) 4618 self.assertFalse(c.isupdate()) 4619 self.assertFalse(c.isdelete()) 4620 self.assertTrue(c.isexecute()) 4621 self.assertFalse(c.isreference()) 4622 self.assertFalse(c.ismembership()) 4623 # 4624 self.assertEqual(c.get_sql_for('grant'), 4625 "GRANT EXECUTE ON PROCEDURE ALL_LANGS TO SYSDBA") 4626 self.assertEqual(c.get_sql_for('grant', grantors=[]), 4627 "GRANT EXECUTE ON PROCEDURE ALL_LANGS TO SYSDBA GRANTED BY SYSDBA") 4628 self.assertEqual(c.get_sql_for('grant', grantors=['SYSDBA', 'TEST_USER']), 4629 "GRANT EXECUTE ON PROCEDURE ALL_LANGS TO SYSDBA") 4630 with self.assertRaises(fdb.ProgrammingError) as cm: 4631 c.get_sql_for('grant', badparam=True) 4632 self.assertTupleEqual(cm.exception.args, 4633 ("Unsupported parameter(s) 'badparam'",)) 4634 self.assertEqual(c.get_sql_for('revoke'), 4635 "REVOKE EXECUTE ON PROCEDURE ALL_LANGS FROM SYSDBA") 4636 self.assertEqual(c.get_sql_for('revoke', grantors=[]), 4637 "REVOKE EXECUTE ON PROCEDURE ALL_LANGS FROM SYSDBA GRANTED BY SYSDBA") 4638 self.assertEqual(c.get_sql_for('revoke', grantors=['SYSDBA', 'TEST_USER']), 4639 "REVOKE EXECUTE ON PROCEDURE ALL_LANGS FROM SYSDBA") 4640 with self.assertRaises(fdb.ProgrammingError) as cm: 4641 c.get_sql_for('revoke', grant_option=True) 4642 self.assertTupleEqual(cm.exception.args, 4643 ("Can't revoke grant option that wasn't granted.",)) 4644 with self.assertRaises(fdb.ProgrammingError) as cm: 4645 c.get_sql_for('revoke', badparam=True) 4646 self.assertTupleEqual(cm.exception.args, 4647 ("Unsupported parameter(s) 'badparam'",)) 4648 c = p.privileges[1] 4649 self.assertEqual(c.get_sql_for('grant'), 4650 "GRANT EXECUTE ON PROCEDURE ALL_LANGS TO PUBLIC WITH GRANT OPTION") 4651 self.assertEqual(c.get_sql_for('revoke'), 4652 "REVOKE EXECUTE ON PROCEDURE ALL_LANGS FROM PUBLIC") 4653 self.assertEqual(c.get_sql_for('revoke', grant_option=True), 4654 "REVOKE GRANT OPTION FOR EXECUTE ON PROCEDURE ALL_LANGS FROM PUBLIC") 4655 # get_privileges_of() 4656 u = fdb.services.User('PUBLIC') 4657 p = self.con.schema.get_privileges_of(u) 4658 if self.con.ods <= fdb.ODS_FB_20: 4659 self.assertEqual(len(p), 66) 4660 elif self.con.ods >= fdb.ODS_FB_30: 4661 self.assertEqual(len(p), 115) 4662 else: 4663 self.assertEqual(len(p), 68) 4664 with self.assertRaises(fdb.ProgrammingError) as cm: 4665 p = self.con.schema.get_privileges_of('PUBLIC') 4666 self.assertTupleEqual(cm.exception.args, 4667 ("Unknown user_type code.",)) 4668 with self.assertRaises(fdb.ProgrammingError) as cm: 4669 p = self.con.schema.get_privileges_of('PUBLIC', 50) 4670 self.assertTupleEqual(cm.exception.args, 4671 ("Unknown user_type code.",)) 4672 # 4673 def testPrivilegeExtended(self): 4674 def get_privilege(obj, privilege): 4675 x = [x for x in obj.privileges if x.privilege == privilege] 4676 return x[0] 4677 p = utils.ObjectList() 4678 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4679 'RDB$PRIVILEGE': 'X', 4680 'RDB$RELATION_NAME': 'ALL_LANGS', 4681 'RDB$OBJECT_TYPE': 5, 4682 'RDB$USER_TYPE': 8, 4683 'RDB$FIELD_NAME': None, 4684 'RDB$GRANTOR': 'SYSDBA', 4685 'RDB$GRANT_OPTION': None})) 4686 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4687 'RDB$PRIVILEGE': 'X', 4688 'RDB$RELATION_NAME': 'ALL_LANGS', 4689 'RDB$OBJECT_TYPE': 5, 4690 'RDB$USER_TYPE': 8, 4691 'RDB$FIELD_NAME': None, 4692 'RDB$GRANTOR': 'SYSDBA', 4693 'RDB$GRANT_OPTION': 1})) 4694 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'T_USER', 4695 'RDB$PRIVILEGE': 'X', 4696 'RDB$RELATION_NAME': 'ALL_LANGS', 4697 'RDB$OBJECT_TYPE': 5, 4698 'RDB$USER_TYPE': 8, 4699 'RDB$FIELD_NAME': None, 4700 'RDB$GRANTOR': 'SYSDBA', 4701 'RDB$GRANT_OPTION': 0})) 4702 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'TEST_ROLE', 4703 'RDB$PRIVILEGE': 'X', 4704 'RDB$RELATION_NAME': 'ALL_LANGS', 4705 'RDB$OBJECT_TYPE': 5, 4706 'RDB$USER_TYPE': 13, 4707 'RDB$FIELD_NAME': None, 4708 'RDB$GRANTOR': 'SYSDBA', 4709 'RDB$GRANT_OPTION': 1})) 4710 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4711 'RDB$PRIVILEGE': 'X', 4712 'RDB$RELATION_NAME': 'ALL_LANGS', 4713 'RDB$OBJECT_TYPE': 5, 4714 'RDB$USER_TYPE': 8, 4715 'RDB$FIELD_NAME': None, 4716 'RDB$GRANTOR': 'T_USER', 4717 'RDB$GRANT_OPTION': 0})) 4718 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4719 'RDB$PRIVILEGE': 'S', 4720 'RDB$RELATION_NAME': 'COUNTRY', 4721 'RDB$OBJECT_TYPE': 0, 4722 'RDB$USER_TYPE': 8, 4723 'RDB$FIELD_NAME': None, 4724 'RDB$GRANTOR': 'SYSDBA', 4725 'RDB$GRANT_OPTION': 1})) 4726 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4727 'RDB$PRIVILEGE': 'I', 4728 'RDB$RELATION_NAME': 'COUNTRY', 4729 'RDB$OBJECT_TYPE': 0, 4730 'RDB$USER_TYPE': 8, 4731 'RDB$FIELD_NAME': None, 4732 'RDB$GRANTOR': 'SYSDBA', 4733 'RDB$GRANT_OPTION': 1})) 4734 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4735 'RDB$PRIVILEGE': 'U', 4736 'RDB$RELATION_NAME': 'COUNTRY', 4737 'RDB$OBJECT_TYPE': 0, 4738 'RDB$USER_TYPE': 8, 4739 'RDB$FIELD_NAME': None, 4740 'RDB$GRANTOR': 'SYSDBA', 4741 'RDB$GRANT_OPTION': 1})) 4742 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4743 'RDB$PRIVILEGE': 'D', 4744 'RDB$RELATION_NAME': 'COUNTRY', 4745 'RDB$OBJECT_TYPE': 0, 4746 'RDB$USER_TYPE': 8, 4747 'RDB$FIELD_NAME': None, 4748 'RDB$GRANTOR': 'SYSDBA', 4749 'RDB$GRANT_OPTION': 1})) 4750 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4751 'RDB$PRIVILEGE': 'R', 4752 'RDB$RELATION_NAME': 'COUNTRY', 4753 'RDB$OBJECT_TYPE': 0, 4754 'RDB$USER_TYPE': 8, 4755 'RDB$FIELD_NAME': None, 4756 'RDB$GRANTOR': 'SYSDBA', 4757 'RDB$GRANT_OPTION': 1})) 4758 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4759 'RDB$PRIVILEGE': 'S', 4760 'RDB$RELATION_NAME': 'COUNTRY', 4761 'RDB$OBJECT_TYPE': 0, 4762 'RDB$USER_TYPE': 8, 4763 'RDB$FIELD_NAME': None, 4764 'RDB$GRANTOR': 'SYSDBA', 4765 'RDB$GRANT_OPTION': 1})) 4766 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4767 'RDB$PRIVILEGE': 'R', 4768 'RDB$RELATION_NAME': 'COUNTRY', 4769 'RDB$OBJECT_TYPE': 0, 4770 'RDB$USER_TYPE': 8, 4771 'RDB$FIELD_NAME': None, 4772 'RDB$GRANTOR': 'SYSDBA', 4773 'RDB$GRANT_OPTION': 1})) 4774 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4775 'RDB$PRIVILEGE': 'I', 4776 'RDB$RELATION_NAME': 'COUNTRY', 4777 'RDB$OBJECT_TYPE': 0, 4778 'RDB$USER_TYPE': 8, 4779 'RDB$FIELD_NAME': None, 4780 'RDB$GRANTOR': 'SYSDBA', 4781 'RDB$GRANT_OPTION': 0})) 4782 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'T_USER', 4783 'RDB$PRIVILEGE': 'U', 4784 'RDB$RELATION_NAME': 'COUNTRY', 4785 'RDB$OBJECT_TYPE': 0, 4786 'RDB$USER_TYPE': 8, 4787 'RDB$FIELD_NAME': 'CURRENCY', 4788 'RDB$GRANTOR': 'SYSDBA', 4789 'RDB$GRANT_OPTION': 0})) 4790 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'T_USER', 4791 'RDB$PRIVILEGE': 'R', 4792 'RDB$RELATION_NAME': 'COUNTRY', 4793 'RDB$OBJECT_TYPE': 0, 4794 'RDB$USER_TYPE': 8, 4795 'RDB$FIELD_NAME': 'COUNTRY', 4796 'RDB$GRANTOR': 'SYSDBA', 4797 'RDB$GRANT_OPTION': 0})) 4798 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'T_USER', 4799 'RDB$PRIVILEGE': 'S', 4800 'RDB$RELATION_NAME': 'COUNTRY', 4801 'RDB$OBJECT_TYPE': 0, 4802 'RDB$USER_TYPE': 8, 4803 'RDB$FIELD_NAME': None, 4804 'RDB$GRANTOR': 'SYSDBA', 4805 'RDB$GRANT_OPTION': 0})) 4806 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'T_USER', 4807 'RDB$PRIVILEGE': 'I', 4808 'RDB$RELATION_NAME': 'COUNTRY', 4809 'RDB$OBJECT_TYPE': 0, 4810 'RDB$USER_TYPE': 8, 4811 'RDB$FIELD_NAME': None, 4812 'RDB$GRANTOR': 'SYSDBA', 4813 'RDB$GRANT_OPTION': 0})) 4814 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'T_USER', 4815 'RDB$PRIVILEGE': 'D', 4816 'RDB$RELATION_NAME': 'COUNTRY', 4817 'RDB$OBJECT_TYPE': 0, 4818 'RDB$USER_TYPE': 8, 4819 'RDB$FIELD_NAME': None, 4820 'RDB$GRANTOR': 'SYSDBA', 4821 'RDB$GRANT_OPTION': 0})) 4822 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'T_USER', 4823 'RDB$PRIVILEGE': 'U', 4824 'RDB$RELATION_NAME': 'COUNTRY', 4825 'RDB$OBJECT_TYPE': 0, 4826 'RDB$USER_TYPE': 8, 4827 'RDB$FIELD_NAME': None, 4828 'RDB$GRANTOR': 'SYSDBA', 4829 'RDB$GRANT_OPTION': 0})) 4830 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'T_USER', 4831 'RDB$PRIVILEGE': 'R', 4832 'RDB$RELATION_NAME': 'COUNTRY', 4833 'RDB$OBJECT_TYPE': 0, 4834 'RDB$USER_TYPE': 8, 4835 'RDB$FIELD_NAME': None, 4836 'RDB$GRANTOR': 'SYSDBA', 4837 'RDB$GRANT_OPTION': 0})) 4838 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'T_USER', 4839 'RDB$PRIVILEGE': 'U', 4840 'RDB$RELATION_NAME': 'COUNTRY', 4841 'RDB$OBJECT_TYPE': 0, 4842 'RDB$USER_TYPE': 8, 4843 'RDB$FIELD_NAME': 'COUNTRY', 4844 'RDB$GRANTOR': 'SYSDBA', 4845 'RDB$GRANT_OPTION': 0})) 4846 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'T_USER', 4847 'RDB$PRIVILEGE': 'R', 4848 'RDB$RELATION_NAME': 'COUNTRY', 4849 'RDB$OBJECT_TYPE': 0, 4850 'RDB$USER_TYPE': 8, 4851 'RDB$FIELD_NAME': 'CURRENCY', 4852 'RDB$GRANTOR': 'SYSDBA', 4853 'RDB$GRANT_OPTION': 0})) 4854 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4855 'RDB$PRIVILEGE': 'D', 4856 'RDB$RELATION_NAME': 'COUNTRY', 4857 'RDB$OBJECT_TYPE': 0, 4858 'RDB$USER_TYPE': 8, 4859 'RDB$FIELD_NAME': None, 4860 'RDB$GRANTOR': 'SYSDBA', 4861 'RDB$GRANT_OPTION': 0})) 4862 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4863 'RDB$PRIVILEGE': 'U', 4864 'RDB$RELATION_NAME': 'COUNTRY', 4865 'RDB$OBJECT_TYPE': 0, 4866 'RDB$USER_TYPE': 8, 4867 'RDB$FIELD_NAME': None, 4868 'RDB$GRANTOR': 'SYSDBA', 4869 'RDB$GRANT_OPTION': 0})) 4870 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4871 'RDB$PRIVILEGE': 'S', 4872 'RDB$RELATION_NAME': 'DEPARTMENT', 4873 'RDB$OBJECT_TYPE': 0, 4874 'RDB$USER_TYPE': 8, 4875 'RDB$FIELD_NAME': None, 4876 'RDB$GRANTOR': 'SYSDBA', 4877 'RDB$GRANT_OPTION': 1})) 4878 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4879 'RDB$PRIVILEGE': 'I', 4880 'RDB$RELATION_NAME': 'DEPARTMENT', 4881 'RDB$OBJECT_TYPE': 0, 4882 'RDB$USER_TYPE': 8, 4883 'RDB$FIELD_NAME': None, 4884 'RDB$GRANTOR': 'SYSDBA', 4885 'RDB$GRANT_OPTION': 1})) 4886 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4887 'RDB$PRIVILEGE': 'U', 4888 'RDB$RELATION_NAME': 'DEPARTMENT', 4889 'RDB$OBJECT_TYPE': 0, 4890 'RDB$USER_TYPE': 8, 4891 'RDB$FIELD_NAME': None, 4892 'RDB$GRANTOR': 'SYSDBA', 4893 'RDB$GRANT_OPTION': 1})) 4894 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4895 'RDB$PRIVILEGE': 'D', 4896 'RDB$RELATION_NAME': 'DEPARTMENT', 4897 'RDB$OBJECT_TYPE': 0, 4898 'RDB$USER_TYPE': 8, 4899 'RDB$FIELD_NAME': None, 4900 'RDB$GRANTOR': 'SYSDBA', 4901 'RDB$GRANT_OPTION': 1})) 4902 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4903 'RDB$PRIVILEGE': 'R', 4904 'RDB$RELATION_NAME': 'DEPARTMENT', 4905 'RDB$OBJECT_TYPE': 0, 4906 'RDB$USER_TYPE': 8, 4907 'RDB$FIELD_NAME': None, 4908 'RDB$GRANTOR': 'SYSDBA', 4909 'RDB$GRANT_OPTION': 1})) 4910 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4911 'RDB$PRIVILEGE': 'S', 4912 'RDB$RELATION_NAME': 'DEPARTMENT', 4913 'RDB$OBJECT_TYPE': 0, 4914 'RDB$USER_TYPE': 8, 4915 'RDB$FIELD_NAME': None, 4916 'RDB$GRANTOR': 'SYSDBA', 4917 'RDB$GRANT_OPTION': 1})) 4918 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4919 'RDB$PRIVILEGE': 'I', 4920 'RDB$RELATION_NAME': 'DEPARTMENT', 4921 'RDB$OBJECT_TYPE': 0, 4922 'RDB$USER_TYPE': 8, 4923 'RDB$FIELD_NAME': None, 4924 'RDB$GRANTOR': 'SYSDBA', 4925 'RDB$GRANT_OPTION': 1})) 4926 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4927 'RDB$PRIVILEGE': 'U', 4928 'RDB$RELATION_NAME': 'DEPARTMENT', 4929 'RDB$OBJECT_TYPE': 0, 4930 'RDB$USER_TYPE': 8, 4931 'RDB$FIELD_NAME': None, 4932 'RDB$GRANTOR': 'SYSDBA', 4933 'RDB$GRANT_OPTION': 1})) 4934 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4935 'RDB$PRIVILEGE': 'D', 4936 'RDB$RELATION_NAME': 'DEPARTMENT', 4937 'RDB$OBJECT_TYPE': 0, 4938 'RDB$USER_TYPE': 8, 4939 'RDB$FIELD_NAME': None, 4940 'RDB$GRANTOR': 'SYSDBA', 4941 'RDB$GRANT_OPTION': 1})) 4942 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4943 'RDB$PRIVILEGE': 'R', 4944 'RDB$RELATION_NAME': 'DEPARTMENT', 4945 'RDB$OBJECT_TYPE': 0, 4946 'RDB$USER_TYPE': 8, 4947 'RDB$FIELD_NAME': None, 4948 'RDB$GRANTOR': 'SYSDBA', 4949 'RDB$GRANT_OPTION': 1})) 4950 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'ORG_CHART', 4951 'RDB$PRIVILEGE': 'S', 4952 'RDB$RELATION_NAME': 'DEPARTMENT', 4953 'RDB$OBJECT_TYPE': 0, 4954 'RDB$USER_TYPE': 5, 4955 'RDB$FIELD_NAME': None, 4956 'RDB$GRANTOR': 'SYSDBA', 4957 'RDB$GRANT_OPTION': 0})) 4958 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4959 'RDB$PRIVILEGE': 'S', 4960 'RDB$RELATION_NAME': 'EMPLOYEE', 4961 'RDB$OBJECT_TYPE': 0, 4962 'RDB$USER_TYPE': 8, 4963 'RDB$FIELD_NAME': None, 4964 'RDB$GRANTOR': 'SYSDBA', 4965 'RDB$GRANT_OPTION': 1})) 4966 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4967 'RDB$PRIVILEGE': 'I', 4968 'RDB$RELATION_NAME': 'EMPLOYEE', 4969 'RDB$OBJECT_TYPE': 0, 4970 'RDB$USER_TYPE': 8, 4971 'RDB$FIELD_NAME': None, 4972 'RDB$GRANTOR': 'SYSDBA', 4973 'RDB$GRANT_OPTION': 1})) 4974 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4975 'RDB$PRIVILEGE': 'U', 4976 'RDB$RELATION_NAME': 'EMPLOYEE', 4977 'RDB$OBJECT_TYPE': 0, 4978 'RDB$USER_TYPE': 8, 4979 'RDB$FIELD_NAME': None, 4980 'RDB$GRANTOR': 'SYSDBA', 4981 'RDB$GRANT_OPTION': 1})) 4982 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4983 'RDB$PRIVILEGE': 'D', 4984 'RDB$RELATION_NAME': 'EMPLOYEE', 4985 'RDB$OBJECT_TYPE': 0, 4986 'RDB$USER_TYPE': 8, 4987 'RDB$FIELD_NAME': None, 4988 'RDB$GRANTOR': 'SYSDBA', 4989 'RDB$GRANT_OPTION': 1})) 4990 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 4991 'RDB$PRIVILEGE': 'R', 4992 'RDB$RELATION_NAME': 'EMPLOYEE', 4993 'RDB$OBJECT_TYPE': 0, 4994 'RDB$USER_TYPE': 8, 4995 'RDB$FIELD_NAME': None, 4996 'RDB$GRANTOR': 'SYSDBA', 4997 'RDB$GRANT_OPTION': 1})) 4998 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 4999 'RDB$PRIVILEGE': 'S', 5000 'RDB$RELATION_NAME': 'EMPLOYEE', 5001 'RDB$OBJECT_TYPE': 0, 5002 'RDB$USER_TYPE': 8, 5003 'RDB$FIELD_NAME': None, 5004 'RDB$GRANTOR': 'SYSDBA', 5005 'RDB$GRANT_OPTION': 1})) 5006 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5007 'RDB$PRIVILEGE': 'I', 5008 'RDB$RELATION_NAME': 'EMPLOYEE', 5009 'RDB$OBJECT_TYPE': 0, 5010 'RDB$USER_TYPE': 8, 5011 'RDB$FIELD_NAME': None, 5012 'RDB$GRANTOR': 'SYSDBA', 5013 'RDB$GRANT_OPTION': 1})) 5014 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5015 'RDB$PRIVILEGE': 'U', 5016 'RDB$RELATION_NAME': 'EMPLOYEE', 5017 'RDB$OBJECT_TYPE': 0, 5018 'RDB$USER_TYPE': 8, 5019 'RDB$FIELD_NAME': None, 5020 'RDB$GRANTOR': 'SYSDBA', 5021 'RDB$GRANT_OPTION': 1})) 5022 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5023 'RDB$PRIVILEGE': 'D', 5024 'RDB$RELATION_NAME': 'EMPLOYEE', 5025 'RDB$OBJECT_TYPE': 0, 5026 'RDB$USER_TYPE': 8, 5027 'RDB$FIELD_NAME': None, 5028 'RDB$GRANTOR': 'SYSDBA', 5029 'RDB$GRANT_OPTION': 1})) 5030 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5031 'RDB$PRIVILEGE': 'R', 5032 'RDB$RELATION_NAME': 'EMPLOYEE', 5033 'RDB$OBJECT_TYPE': 0, 5034 'RDB$USER_TYPE': 8, 5035 'RDB$FIELD_NAME': None, 5036 'RDB$GRANTOR': 'SYSDBA', 5037 'RDB$GRANT_OPTION': 1})) 5038 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'ORG_CHART', 5039 'RDB$PRIVILEGE': 'S', 5040 'RDB$RELATION_NAME': 'EMPLOYEE', 5041 'RDB$OBJECT_TYPE': 0, 5042 'RDB$USER_TYPE': 5, 5043 'RDB$FIELD_NAME': None, 5044 'RDB$GRANTOR': 'SYSDBA', 5045 'RDB$GRANT_OPTION': 0})) 5046 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5047 'RDB$PRIVILEGE': 'X', 5048 'RDB$RELATION_NAME': 'ORG_CHART', 5049 'RDB$OBJECT_TYPE': 5, 5050 'RDB$USER_TYPE': 8, 5051 'RDB$FIELD_NAME': None, 5052 'RDB$GRANTOR': 'SYSDBA', 5053 'RDB$GRANT_OPTION': None})) 5054 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5055 'RDB$PRIVILEGE': 'X', 5056 'RDB$RELATION_NAME': 'ORG_CHART', 5057 'RDB$OBJECT_TYPE': 5, 5058 'RDB$USER_TYPE': 8, 5059 'RDB$FIELD_NAME': None, 5060 'RDB$GRANTOR': 'SYSDBA', 5061 'RDB$GRANT_OPTION': 1})) 5062 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5063 'RDB$PRIVILEGE': 'S', 5064 'RDB$RELATION_NAME': 'PHONE_LIST', 5065 'RDB$OBJECT_TYPE': 0, 5066 'RDB$USER_TYPE': 8, 5067 'RDB$FIELD_NAME': None, 5068 'RDB$GRANTOR': 'SYSDBA', 5069 'RDB$GRANT_OPTION': 1})) 5070 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5071 'RDB$PRIVILEGE': 'I', 5072 'RDB$RELATION_NAME': 'PHONE_LIST', 5073 'RDB$OBJECT_TYPE': 0, 5074 'RDB$USER_TYPE': 8, 5075 'RDB$FIELD_NAME': None, 5076 'RDB$GRANTOR': 'SYSDBA', 5077 'RDB$GRANT_OPTION': 1})) 5078 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5079 'RDB$PRIVILEGE': 'U', 5080 'RDB$RELATION_NAME': 'PHONE_LIST', 5081 'RDB$OBJECT_TYPE': 0, 5082 'RDB$USER_TYPE': 8, 5083 'RDB$FIELD_NAME': None, 5084 'RDB$GRANTOR': 'SYSDBA', 5085 'RDB$GRANT_OPTION': 1})) 5086 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5087 'RDB$PRIVILEGE': 'D', 5088 'RDB$RELATION_NAME': 'PHONE_LIST', 5089 'RDB$OBJECT_TYPE': 0, 5090 'RDB$USER_TYPE': 8, 5091 'RDB$FIELD_NAME': None, 5092 'RDB$GRANTOR': 'SYSDBA', 5093 'RDB$GRANT_OPTION': 1})) 5094 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5095 'RDB$PRIVILEGE': 'R', 5096 'RDB$RELATION_NAME': 'PHONE_LIST', 5097 'RDB$OBJECT_TYPE': 0, 5098 'RDB$USER_TYPE': 8, 5099 'RDB$FIELD_NAME': None, 5100 'RDB$GRANTOR': 'SYSDBA', 5101 'RDB$GRANT_OPTION': 1})) 5102 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5103 'RDB$PRIVILEGE': 'S', 5104 'RDB$RELATION_NAME': 'PHONE_LIST', 5105 'RDB$OBJECT_TYPE': 0, 5106 'RDB$USER_TYPE': 8, 5107 'RDB$FIELD_NAME': None, 5108 'RDB$GRANTOR': 'SYSDBA', 5109 'RDB$GRANT_OPTION': 1})) 5110 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5111 'RDB$PRIVILEGE': 'I', 5112 'RDB$RELATION_NAME': 'PHONE_LIST', 5113 'RDB$OBJECT_TYPE': 0, 5114 'RDB$USER_TYPE': 8, 5115 'RDB$FIELD_NAME': None, 5116 'RDB$GRANTOR': 'SYSDBA', 5117 'RDB$GRANT_OPTION': 1})) 5118 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5119 'RDB$PRIVILEGE': 'U', 5120 'RDB$RELATION_NAME': 'PHONE_LIST', 5121 'RDB$OBJECT_TYPE': 0, 5122 'RDB$USER_TYPE': 8, 5123 'RDB$FIELD_NAME': None, 5124 'RDB$GRANTOR': 'SYSDBA', 5125 'RDB$GRANT_OPTION': 1})) 5126 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5127 'RDB$PRIVILEGE': 'D', 5128 'RDB$RELATION_NAME': 'PHONE_LIST', 5129 'RDB$OBJECT_TYPE': 0, 5130 'RDB$USER_TYPE': 8, 5131 'RDB$FIELD_NAME': None, 5132 'RDB$GRANTOR': 'SYSDBA', 5133 'RDB$GRANT_OPTION': 1})) 5134 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5135 'RDB$PRIVILEGE': 'R', 5136 'RDB$RELATION_NAME': 'PHONE_LIST', 5137 'RDB$OBJECT_TYPE': 0, 5138 'RDB$USER_TYPE': 8, 5139 'RDB$FIELD_NAME': None, 5140 'RDB$GRANTOR': 'SYSDBA', 5141 'RDB$GRANT_OPTION': 1})) 5142 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5143 'RDB$PRIVILEGE': 'R', 5144 'RDB$RELATION_NAME': 'PHONE_LIST', 5145 'RDB$OBJECT_TYPE': 0, 5146 'RDB$USER_TYPE': 8, 5147 'RDB$FIELD_NAME': 'EMP_NO', 5148 'RDB$GRANTOR': 'SYSDBA', 5149 'RDB$GRANT_OPTION': 0})) 5150 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5151 'RDB$PRIVILEGE': 'S', 5152 'RDB$RELATION_NAME': 'RDB$PAGES', 5153 'RDB$OBJECT_TYPE': 0, 5154 'RDB$USER_TYPE': 8, 5155 'RDB$FIELD_NAME': None, 5156 'RDB$GRANTOR': 'SYSDBA', 5157 'RDB$GRANT_OPTION': 1})) 5158 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5159 'RDB$PRIVILEGE': 'I', 5160 'RDB$RELATION_NAME': 'RDB$PAGES', 5161 'RDB$OBJECT_TYPE': 0, 5162 'RDB$USER_TYPE': 8, 5163 'RDB$FIELD_NAME': None, 5164 'RDB$GRANTOR': 'SYSDBA', 5165 'RDB$GRANT_OPTION': 1})) 5166 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5167 'RDB$PRIVILEGE': 'U', 5168 'RDB$RELATION_NAME': 'RDB$PAGES', 5169 'RDB$OBJECT_TYPE': 0, 5170 'RDB$USER_TYPE': 8, 5171 'RDB$FIELD_NAME': None, 5172 'RDB$GRANTOR': 'SYSDBA', 5173 'RDB$GRANT_OPTION': 1})) 5174 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5175 'RDB$PRIVILEGE': 'D', 5176 'RDB$RELATION_NAME': 'RDB$PAGES', 5177 'RDB$OBJECT_TYPE': 0, 5178 'RDB$USER_TYPE': 8, 5179 'RDB$FIELD_NAME': None, 5180 'RDB$GRANTOR': 'SYSDBA', 5181 'RDB$GRANT_OPTION': 1})) 5182 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5183 'RDB$PRIVILEGE': 'R', 5184 'RDB$RELATION_NAME': 'RDB$PAGES', 5185 'RDB$OBJECT_TYPE': 0, 5186 'RDB$USER_TYPE': 8, 5187 'RDB$FIELD_NAME': None, 5188 'RDB$GRANTOR': 'SYSDBA', 5189 'RDB$GRANT_OPTION': 1})) 5190 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5191 'RDB$PRIVILEGE': 'S', 5192 'RDB$RELATION_NAME': 'RDB$PAGES', 5193 'RDB$OBJECT_TYPE': 0, 5194 'RDB$USER_TYPE': 8, 5195 'RDB$FIELD_NAME': None, 5196 'RDB$GRANTOR': 'SYSDBA', 5197 'RDB$GRANT_OPTION': 0})) 5198 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SYSDBA', 5199 'RDB$PRIVILEGE': 'X', 5200 'RDB$RELATION_NAME': 'SHIP_ORDER', 5201 'RDB$OBJECT_TYPE': 5, 5202 'RDB$USER_TYPE': 8, 5203 'RDB$FIELD_NAME': None, 5204 'RDB$GRANTOR': 'SYSDBA', 5205 'RDB$GRANT_OPTION': None})) 5206 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PUBLIC', 5207 'RDB$PRIVILEGE': 'X', 5208 'RDB$RELATION_NAME': 'SHIP_ORDER', 5209 'RDB$OBJECT_TYPE': 5, 5210 'RDB$USER_TYPE': 8, 5211 'RDB$FIELD_NAME': None, 5212 'RDB$GRANTOR': 'SYSDBA', 5213 'RDB$GRANT_OPTION': 1})) 5214 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'T_USER', 5215 'RDB$PRIVILEGE': 'M', 5216 'RDB$RELATION_NAME': 'TEST_ROLE', 5217 'RDB$OBJECT_TYPE': 13, 5218 'RDB$USER_TYPE': 8, 5219 'RDB$FIELD_NAME': None, 5220 'RDB$GRANTOR': 'SYSDBA', 5221 'RDB$GRANT_OPTION': 0})) 5222 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'SAVE_SALARY_CHANGE', 5223 'RDB$PRIVILEGE': 'I', 5224 'RDB$RELATION_NAME': 'SALARY_HISTORY', 5225 'RDB$OBJECT_TYPE': 0, 5226 'RDB$USER_TYPE': 2, 5227 'RDB$FIELD_NAME': None, 5228 'RDB$GRANTOR': 'SYSDBA', 5229 'RDB$GRANT_OPTION': 0})) 5230 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PHONE_LIST', 5231 'RDB$PRIVILEGE': 'S', 5232 'RDB$RELATION_NAME': 'DEPARTMENT', 5233 'RDB$OBJECT_TYPE': 0, 5234 'RDB$USER_TYPE': 1, 5235 'RDB$FIELD_NAME': None, 5236 'RDB$GRANTOR': 'SYSDBA', 5237 'RDB$GRANT_OPTION': 0})) 5238 p.append(sm.Privilege(self.con.schema, {'RDB$USER': 'PHONE_LIST', 5239 'RDB$PRIVILEGE': 'S', 5240 'RDB$RELATION_NAME': 'EMPLOYEE', 5241 'RDB$OBJECT_TYPE': 0, 5242 'RDB$USER_TYPE': 1, 5243 'RDB$FIELD_NAME': None, 5244 'RDB$GRANTOR': 'SYSDBA', 5245 'RDB$GRANT_OPTION': 0})) 5246 # 5247 self.con.schema.__dict__['_Schema__privileges'] = p 5248 # Table 5249 p = self.con.schema.get_table('COUNTRY') 5250 self.assertEqual(len(p.privileges), 19) 5251 self.assertEqual(len([x for x in p.privileges if x.user_name == 'SYSDBA']), 5) 5252 self.assertEqual(len([x for x in p.privileges if x.user_name == 'PUBLIC']), 5) 5253 self.assertEqual(len([x for x in p.privileges if x.user_name == 'T_USER']), 9) 5254 # 5255 self.assertTrue(get_privilege(p, 'S').isselect()) 5256 self.assertTrue(get_privilege(p, 'I').isinsert()) 5257 self.assertTrue(get_privilege(p, 'U').isupdate()) 5258 self.assertTrue(get_privilege(p, 'D').isdelete()) 5259 self.assertTrue(get_privilege(p, 'R').isreference()) 5260 # 5261 x = p.privileges[0] 5262 self.assertIsInstance(x.subject, sm.Table) 5263 self.assertEqual(x.subject.name, p.name) 5264 # TableColumn 5265 p = p.get_column('CURRENCY') 5266 self.assertEqual(len(p.privileges), 2) 5267 x = p.privileges[0] 5268 self.assertIsInstance(x.subject, sm.Table) 5269 self.assertEqual(x.field_name, p.name) 5270 # View 5271 p = self.con.schema.get_view('PHONE_LIST') 5272 self.assertEqual(len(p.privileges), 11) 5273 self.assertEqual(len([x for x in p.privileges if x.user_name == 'SYSDBA']), 5) 5274 self.assertEqual(len([x for x in p.privileges if x.user_name == 'PUBLIC']), 6) 5275 # 5276 x = p.privileges[0] 5277 self.assertIsInstance(x.subject, sm.View) 5278 self.assertEqual(x.subject.name, p.name) 5279 # ViewColumn 5280 p = p.get_column('EMP_NO') 5281 self.assertEqual(len(p.privileges), 1) 5282 x = p.privileges[0] 5283 self.assertIsInstance(x.subject, sm.View) 5284 self.assertEqual(x.field_name, p.name) 5285 # Procedure 5286 p = self.con.schema.get_procedure('ORG_CHART') 5287 self.assertEqual(len(p.privileges), 2) 5288 self.assertEqual(len([x for x in p.privileges if x.user_name == 'SYSDBA']), 1) 5289 self.assertEqual(len([x for x in p.privileges if x.user_name == 'PUBLIC']), 1) 5290 # 5291 x = p.privileges[0] 5292 self.assertFalse(x.has_grant()) 5293 self.assertIsInstance(x.subject, sm.Procedure) 5294 self.assertEqual(x.subject.name, p.name) 5295 # 5296 x = p.privileges[1] 5297 self.assertTrue(x.has_grant()) 5298 # Role 5299 p = self.con.schema.get_role('TEST_ROLE') 5300 self.assertEqual(len(p.privileges), 1) 5301 x = p.privileges[0] 5302 self.assertIsInstance(x.user, sm.Role) 5303 self.assertEqual(x.user.name, p.name) 5304 self.assertTrue(x.isexecute()) 5305 # Trigger as grantee 5306 p = self.con.schema.get_table('SALARY_HISTORY') 5307 x = p.privileges[0] 5308 self.assertIsInstance(x.user, sm.Trigger) 5309 self.assertEqual(x.user.name, 'SAVE_SALARY_CHANGE') 5310 # View as grantee 5311 p = self.con.schema.get_view('PHONE_LIST') 5312 x = self.con.schema.get_privileges_of(p) 5313 self.assertEqual(len(x), 2) 5314 x = x[0] 5315 self.assertIsInstance(x.user, sm.View) 5316 self.assertEqual(x.user.name, 'PHONE_LIST') 5317 # get_grants() 5318 self.assertListEqual(sm.get_grants(p.privileges), 5319 ['GRANT REFERENCES(EMP_NO) ON PHONE_LIST TO PUBLIC', 5320 'GRANT DELETE, INSERT, REFERENCES, SELECT, UPDATE ON PHONE_LIST TO PUBLIC WITH GRANT OPTION', 5321 'GRANT DELETE, INSERT, REFERENCES, SELECT, UPDATE ON PHONE_LIST TO SYSDBA WITH GRANT OPTION']) 5322 p = self.con.schema.get_table('COUNTRY') 5323 self.assertListEqual(sm.get_grants(p.privileges), 5324 ['GRANT DELETE, INSERT, UPDATE ON COUNTRY TO PUBLIC', 5325 'GRANT REFERENCES, SELECT ON COUNTRY TO PUBLIC WITH GRANT OPTION', 5326 'GRANT DELETE, INSERT, REFERENCES, SELECT, UPDATE ON COUNTRY TO SYSDBA WITH GRANT OPTION', 5327 'GRANT DELETE, INSERT, REFERENCES(COUNTRY,CURRENCY), SELECT, UPDATE(COUNTRY,CURRENCY) ON COUNTRY TO T_USER']) 5328 p = self.con.schema.get_role('TEST_ROLE') 5329 self.assertListEqual(sm.get_grants(p.privileges), ['GRANT EXECUTE ON PROCEDURE ALL_LANGS TO TEST_ROLE WITH GRANT OPTION']) 5330 p = self.con.schema.get_table('SALARY_HISTORY') 5331 self.assertListEqual(sm.get_grants(p.privileges), 5332 ['GRANT INSERT ON SALARY_HISTORY TO TRIGGER SAVE_SALARY_CHANGE']) 5333 p = self.con.schema.get_procedure('ORG_CHART') 5334 self.assertListEqual(sm.get_grants(p.privileges), 5335 ['GRANT EXECUTE ON PROCEDURE ORG_CHART TO PUBLIC WITH GRANT OPTION', 5336 'GRANT EXECUTE ON PROCEDURE ORG_CHART TO SYSDBA']) 5337 # 5338 def testPackage(self): 5339 if self.con.ods < fdb.ODS_FB_30: 5340 return 5341 c = self.con.schema.get_package('TEST') 5342 # common properties 5343 self.assertEqual(c.name, 'TEST') 5344 self.assertIsNone(c.description) 5345 self.assertFalse(c.issystemobject()) 5346 self.assertListEqual(c.actions, 5347 ['create', 'recreate', 'create_or_alter', 'alter', 'drop']) 5348 self.assertEqual(c.get_quoted_name(), 'TEST') 5349 self.assertEqual(c.owner_name, 'SYSDBA') 5350 self.assertEqual(c.security_class, 'SQL$575') 5351 self.assertEqual(c.header, """BEGIN 5352 PROCEDURE P1(I INT) RETURNS (O INT); -- public procedure 5353 FUNCTION F(X INT) RETURNS INT; 5354END""") 5355 self.assertEqual(c.body, """BEGIN 5356 FUNCTION F1(I INT) RETURNS INT; -- private function 5357 5358 PROCEDURE P1(I INT) RETURNS (O INT) 5359 AS 5360 BEGIN 5361 END 5362 5363 FUNCTION F1(I INT) RETURNS INT 5364 AS 5365 BEGIN 5366 RETURN F(I)+10; 5367 END 5368 5369 FUNCTION F(X INT) RETURNS INT 5370 AS 5371 BEGIN 5372 RETURN X+1; 5373 END 5374END""") 5375 self.assertListEqual(c.get_dependents(), []) 5376 self.assertEqual(len(c.get_dependencies()), 1) 5377 self.assertEqual(len(c.functions), 2) 5378 self.assertEqual(len(c.procedures), 1) 5379 # 5380 self.assertEqual(c.get_sql_for('create'), """CREATE PACKAGE TEST 5381AS 5382BEGIN 5383 PROCEDURE P1(I INT) RETURNS (O INT); -- public procedure 5384 FUNCTION F(X INT) RETURNS INT; 5385END""") 5386 self.assertEqual(c.get_sql_for('create', body=True), """CREATE PACKAGE BODY TEST 5387AS 5388BEGIN 5389 FUNCTION F1(I INT) RETURNS INT; -- private function 5390 5391 PROCEDURE P1(I INT) RETURNS (O INT) 5392 AS 5393 BEGIN 5394 END 5395 5396 FUNCTION F1(I INT) RETURNS INT 5397 AS 5398 BEGIN 5399 RETURN F(I)+10; 5400 END 5401 5402 FUNCTION F(X INT) RETURNS INT 5403 AS 5404 BEGIN 5405 RETURN X+1; 5406 END 5407END""") 5408 self.assertEqual(c.get_sql_for('alter', header="FUNCTION F2(I INT) RETURNS INT;"), 5409 """ALTER PACKAGE TEST 5410AS 5411BEGIN 5412FUNCTION F2(I INT) RETURNS INT; 5413END""") 5414 self.assertEqual(c.get_sql_for('drop'), """DROP PACKAGE TEST""") 5415 self.assertEqual(c.get_sql_for('drop', body=True), """DROP PACKAGE BODY TEST""") 5416 self.assertEqual(c.get_sql_for('create_or_alter'), """CREATE OR ALTER PACKAGE TEST 5417AS 5418BEGIN 5419 PROCEDURE P1(I INT) RETURNS (O INT); -- public procedure 5420 FUNCTION F(X INT) RETURNS INT; 5421END""") 5422 # 5423 def testVisitor(self): 5424 v = SchemaVisitor(self, 'create', follow='dependencies') 5425 c = self.con.schema.get_procedure('ALL_LANGS') 5426 c.accept(v) 5427 self.maxDiff = None 5428 output = "CREATE TABLE JOB (\n JOB_CODE JOBCODE NOT NULL,\n" \ 5429 " JOB_GRADE JOBGRADE NOT NULL,\n" \ 5430 " JOB_COUNTRY COUNTRYNAME NOT NULL,\n" \ 5431 " JOB_TITLE VARCHAR(25) NOT NULL,\n" \ 5432 " MIN_SALARY SALARY NOT NULL,\n" \ 5433 " MAX_SALARY SALARY NOT NULL,\n" \ 5434 " JOB_REQUIREMENT BLOB SUB_TYPE TEXT SEGMENT SIZE 400,\n" \ 5435 " LANGUAGE_REQ VARCHAR(15)[5],\n" \ 5436 " PRIMARY KEY (JOB_CODE,JOB_GRADE,JOB_COUNTRY)\n" \ 5437 ")\n" \ 5438 "CREATE PROCEDURE SHOW_LANGS (\n" \ 5439 " CODE VARCHAR(5),\n" \ 5440 " GRADE SMALLINT,\n" \ 5441 " CTY VARCHAR(15)\n" \ 5442 ")\n" \ 5443 "RETURNS (LANGUAGES VARCHAR(15))\n" \ 5444 "AS\n" \ 5445 "DECLARE VARIABLE i INTEGER;\n" \ 5446 "BEGIN\n" \ 5447 " i = 1;\n" \ 5448 " WHILE (i <= 5) DO\n" \ 5449 " BEGIN\n" \ 5450 " SELECT language_req[:i] FROM joB\n" \ 5451 " WHERE ((job_code = :code) AND (job_grade = :grade) AND (job_country = :cty)\n" \ 5452 " AND (language_req IS NOT NULL))\n" \ 5453 " INTO :languages;\n" \ 5454 " IF (languages = ' ') THEN /* Prints 'NULL' instead of blanks */\n" \ 5455 " languages = 'NULL'; \n" \ 5456 " i = i +1;\n" \ 5457 " SUSPEND;\n" \ 5458 " END\nEND\nCREATE PROCEDURE ALL_LANGS\n" \ 5459 "RETURNS (\n" \ 5460 " CODE VARCHAR(5),\n" \ 5461 " GRADE VARCHAR(5),\n" \ 5462 " COUNTRY VARCHAR(15),\n" \ 5463 " LANG VARCHAR(15)\n" \ 5464 ")\n" \ 5465 "AS\n" \ 5466 "BEGIN\n" \ 5467 "\tFOR SELECT job_code, job_grade, job_country FROM job \n" \ 5468 "\t\tINTO :code, :grade, :country\n" \ 5469 "\n" \ 5470 "\tDO\n" \ 5471 "\tBEGIN\n" \ 5472 "\t FOR SELECT languages FROM show_langs \n" \ 5473 " \t\t (:code, :grade, :country) INTO :lang DO\n" \ 5474 "\t SUSPEND;\n" \ 5475 "\t /* Put nice separators between rows */\n" \ 5476 "\t code = '=====';\n" \ 5477 "\t grade = '=====';\n" \ 5478 "\t country = '===============';\n" \ 5479 "\t lang = '==============';\n" \ 5480 "\t SUSPEND;\n" \ 5481 "\tEND\n" \ 5482 " END\n" 5483 self.assertMultiLineEqual(self.output.getvalue(), output) 5484 5485 v = SchemaVisitor(self, 'drop', follow='dependents') 5486 c = self.con.schema.get_table('JOB') 5487 self.clear_output() 5488 c.accept(v) 5489 self.assertEqual(self.output.getvalue(), """DROP PROCEDURE ALL_LANGS 5490DROP PROCEDURE SHOW_LANGS 5491DROP TABLE JOB 5492""") 5493 5494 def testScript(self): 5495 self.maxDiff = None 5496 self.assertEqual(25, len(sm.SCRIPT_DEFAULT_ORDER)) 5497 s = self.con.schema 5498 script = s.get_metadata_ddl([sm.SCRIPT_COLLATIONS]) 5499 self.assertListEqual(script, ["""CREATE COLLATION TEST_COLLATE 5500 FOR WIN1250 5501 FROM WIN_CZ 5502 NO PAD 5503 CASE INSENSITIVE 5504 ACCENT INSENSITIVE 5505 'DISABLE-COMPRESSIONS=0;DISABLE-EXPANSIONS=0'"""]) 5506 script = s.get_metadata_ddl([sm.SCRIPT_CHARACTER_SETS]) 5507 self.assertListEqual(script, []) 5508 script = s.get_metadata_ddl([sm.SCRIPT_UDFS]) 5509 self.assertListEqual(script, []) 5510 script = s.get_metadata_ddl([sm.SCRIPT_GENERATORS]) 5511 self.assertListEqual(script, ['CREATE SEQUENCE EMP_NO_GEN', 5512 'CREATE SEQUENCE CUST_NO_GEN']) 5513 script = s.get_metadata_ddl([sm.SCRIPT_EXCEPTIONS]) 5514 self.assertListEqual(script, ["CREATE EXCEPTION UNKNOWN_EMP_ID 'Invalid employee number or project id.'", 5515 "CREATE EXCEPTION REASSIGN_SALES 'Reassign the sales records before deleting this employee.'", 5516 'CREATE EXCEPTION ORDER_ALREADY_SHIPPED \'Order status is "shipped."\'', 5517 "CREATE EXCEPTION CUSTOMER_ON_HOLD 'This customer is on hold.'", 5518 "CREATE EXCEPTION CUSTOMER_CHECK 'Overdue balance -- can not ship.'"]) 5519 script = s.get_metadata_ddl([sm.SCRIPT_DOMAINS]) 5520 self.assertListEqual(script, ['CREATE DOMAIN "FIRSTNAME" AS VARCHAR(15)', 5521 'CREATE DOMAIN "LASTNAME" AS VARCHAR(20)', 5522 'CREATE DOMAIN PHONENUMBER AS VARCHAR(20)', 5523 'CREATE DOMAIN COUNTRYNAME AS VARCHAR(15)', 5524 'CREATE DOMAIN ADDRESSLINE AS VARCHAR(30)', 5525 'CREATE DOMAIN EMPNO AS SMALLINT', 5526 "CREATE DOMAIN DEPTNO AS CHAR(3) CHECK (VALUE = '000' OR (VALUE > '0' AND VALUE <= '999') OR VALUE IS NULL)", 5527 'CREATE DOMAIN PROJNO AS CHAR(5) CHECK (VALUE = UPPER (VALUE))', 5528 'CREATE DOMAIN CUSTNO AS INTEGER CHECK (VALUE > 1000)', 5529 "CREATE DOMAIN JOBCODE AS VARCHAR(5) CHECK (VALUE > '99999')", 5530 'CREATE DOMAIN JOBGRADE AS SMALLINT CHECK (VALUE BETWEEN 0 AND 6)', 5531 'CREATE DOMAIN SALARY AS NUMERIC(10, 2) DEFAULT 0 CHECK (VALUE > 0)', 5532 'CREATE DOMAIN BUDGET AS DECIMAL(12, 2) DEFAULT 50000 CHECK (VALUE > 10000 AND VALUE <= 2000000)', 5533 "CREATE DOMAIN PRODTYPE AS VARCHAR(12) DEFAULT 'software' NOT NULL CHECK (VALUE IN ('software', 'hardware', 'other', 'N/A'))", 5534 "CREATE DOMAIN PONUMBER AS CHAR(8) CHECK (VALUE STARTING WITH 'V')"]) 5535 if self.version == FB30: 5536 script = s.get_metadata_ddl([sm.SCRIPT_PACKAGE_DEFS]) 5537 self.assertListEqual(script, ['CREATE PACKAGE TEST\nAS\nBEGIN\n PROCEDURE P1(I INT) RETURNS (O INT); -- public procedure\n FUNCTION F(X INT) RETURNS INT;\nEND', 5538 'CREATE PACKAGE TEST2\nAS\nBEGIN\n FUNCTION F3(X INT) RETURNS INT;\nEND']) 5539 if self.version == FB30: 5540 script = s.get_metadata_ddl([sm.SCRIPT_FUNCTION_DEFS]) 5541 self.assertListEqual(script, ['CREATE FUNCTION F2 (X INTEGER)\nRETURNS INTEGER\nAS\nBEGIN\nEND', 5542 'CREATE FUNCTION FX (\n F TYPE OF "FIRSTNAME",\n L TYPE OF COLUMN CUSTOMER.CONTACT_LAST\n)\nRETURNS VARCHAR(35)\nAS\nBEGIN\nEND', 5543 'CREATE FUNCTION FN\nRETURNS INTEGER\nAS\nBEGIN\nEND']) 5544 script = s.get_metadata_ddl([sm.SCRIPT_PROCEDURE_DEFS]) 5545 if self.version == FB30: 5546 self.assertListEqual(script, ['CREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT)\nRETURNS (PROJ_ID CHAR(5))\nAS\nBEGIN\n SUSPEND;\nEND', 5547 'CREATE PROCEDURE ADD_EMP_PROJ (\n EMP_NO SMALLINT,\n PROJ_ID CHAR(5)\n)\nAS\nBEGIN\n SUSPEND;\nEND', 5548 'CREATE PROCEDURE SUB_TOT_BUDGET (HEAD_DEPT CHAR(3))\nRETURNS (\n TOT_BUDGET DECIMAL(12, 2),\n AVG_BUDGET DECIMAL(12, 2),\n MIN_BUDGET DECIMAL(12, 2),\n MAX_BUDGET DECIMAL(12, 2)\n)\nAS\nBEGIN\n SUSPEND;\nEND', 5549 'CREATE PROCEDURE DELETE_EMPLOYEE (EMP_NUM INTEGER)\nAS\nBEGIN\n SUSPEND;\nEND', 5550 'CREATE PROCEDURE DEPT_BUDGET (DNO CHAR(3))\nRETURNS (TOT DECIMAL(12, 2))\nAS\nBEGIN\n SUSPEND;\nEND', 5551 'CREATE PROCEDURE ORG_CHART\nRETURNS (\n HEAD_DEPT CHAR(25),\n DEPARTMENT CHAR(25),\n MNGR_NAME CHAR(20),\n TITLE CHAR(5),\n EMP_CNT INTEGER\n)\nAS\nBEGIN\n SUSPEND;\nEND', 5552 'CREATE PROCEDURE MAIL_LABEL (CUST_NO INTEGER)\nRETURNS (\n LINE1 CHAR(40),\n LINE2 CHAR(40),\n LINE3 CHAR(40),\n LINE4 CHAR(40),\n LINE5 CHAR(40),\n LINE6 CHAR(40)\n)\nAS\nBEGIN\n SUSPEND;\nEND', 5553 'CREATE PROCEDURE SHIP_ORDER (PO_NUM CHAR(8))\nAS\nBEGIN\n SUSPEND;\nEND', 5554 'CREATE PROCEDURE SHOW_LANGS (\n CODE VARCHAR(5),\n GRADE SMALLINT,\n CTY VARCHAR(15)\n)\nRETURNS (LANGUAGES VARCHAR(15))\nAS\nBEGIN\n SUSPEND;\nEND', 5555 'CREATE PROCEDURE ALL_LANGS\nRETURNS (\n CODE VARCHAR(5),\n GRADE VARCHAR(5),\n COUNTRY VARCHAR(15),\n LANG VARCHAR(15)\n)\nAS\nBEGIN\n SUSPEND;\nEND']) 5556 else: 5557 self.assertListEqual(script, ['CREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT)\nRETURNS (PROJ_ID CHAR(5))\nAS\nBEGIN\nEND', 5558 'CREATE PROCEDURE ADD_EMP_PROJ (\n EMP_NO SMALLINT,\n PROJ_ID CHAR(5)\n)\nAS\nBEGIN\nEND', 5559 'CREATE PROCEDURE SUB_TOT_BUDGET (HEAD_DEPT CHAR(3))\nRETURNS (\n TOT_BUDGET DECIMAL(12, 2),\n AVG_BUDGET DECIMAL(12, 2),\n MIN_BUDGET DECIMAL(12, 2),\n MAX_BUDGET DECIMAL(12, 2)\n)\nAS\nBEGIN\nEND', 5560 'CREATE PROCEDURE DELETE_EMPLOYEE (EMP_NUM INTEGER)\nAS\nBEGIN\nEND', 5561 'CREATE PROCEDURE DEPT_BUDGET (DNO CHAR(3))\nRETURNS (TOT DECIMAL(12, 2))\nAS\nBEGIN\nEND', 5562 'CREATE PROCEDURE ORG_CHART\nRETURNS (\n HEAD_DEPT CHAR(25),\n DEPARTMENT CHAR(25),\n MNGR_NAME CHAR(20),\n TITLE CHAR(5),\n EMP_CNT INTEGER\n)\nAS\nBEGIN\nEND', 5563 'CREATE PROCEDURE MAIL_LABEL (CUST_NO INTEGER)\nRETURNS (\n LINE1 CHAR(40),\n LINE2 CHAR(40),\n LINE3 CHAR(40),\n LINE4 CHAR(40),\n LINE5 CHAR(40),\n LINE6 CHAR(40)\n)\nAS\nBEGIN\nEND', 5564 'CREATE PROCEDURE SHIP_ORDER (PO_NUM CHAR(8))\nAS\nBEGIN\nEND', 5565 'CREATE PROCEDURE SHOW_LANGS (\n CODE VARCHAR(5),\n GRADE SMALLINT,\n CTY VARCHAR(15)\n)\nRETURNS (LANGUAGES VARCHAR(15))\nAS\nBEGIN\nEND', 5566 'CREATE PROCEDURE ALL_LANGS\nRETURNS (\n CODE VARCHAR(5),\n GRADE VARCHAR(5),\n COUNTRY VARCHAR(15),\n LANG VARCHAR(15)\n)\nAS\nBEGIN\nEND']) 5567 script = s.get_metadata_ddl([sm.SCRIPT_TABLES]) 5568 if self.version == FB30: 5569 self.assertListEqual(script, ['CREATE TABLE COUNTRY (\n COUNTRY COUNTRYNAME NOT NULL,\n CURRENCY VARCHAR(10) NOT NULL\n)', 5570 'CREATE TABLE JOB (\n JOB_CODE JOBCODE NOT NULL,\n JOB_GRADE JOBGRADE NOT NULL,\n JOB_COUNTRY COUNTRYNAME NOT NULL,\n JOB_TITLE VARCHAR(25) NOT NULL,\n MIN_SALARY SALARY NOT NULL,\n MAX_SALARY SALARY NOT NULL,\n JOB_REQUIREMENT BLOB SUB_TYPE TEXT SEGMENT SIZE 400,\n LANGUAGE_REQ VARCHAR(15)[5]\n)', 5571 "CREATE TABLE DEPARTMENT (\n DEPT_NO DEPTNO NOT NULL,\n DEPARTMENT VARCHAR(25) NOT NULL,\n HEAD_DEPT DEPTNO,\n MNGR_NO EMPNO,\n BUDGET BUDGET,\n LOCATION VARCHAR(15),\n PHONE_NO PHONENUMBER DEFAULT '555-1234'\n)", 5572 'CREATE TABLE EMPLOYEE (\n EMP_NO EMPNO NOT NULL,\n FIRST_NAME "FIRSTNAME" NOT NULL,\n LAST_NAME "LASTNAME" NOT NULL,\n PHONE_EXT VARCHAR(4),\n HIRE_DATE TIMESTAMP DEFAULT \'NOW\' NOT NULL,\n DEPT_NO DEPTNO NOT NULL,\n JOB_CODE JOBCODE NOT NULL,\n JOB_GRADE JOBGRADE NOT NULL,\n JOB_COUNTRY COUNTRYNAME NOT NULL,\n SALARY SALARY NOT NULL,\n FULL_NAME COMPUTED BY (last_name || \', \' || first_name)\n)', 5573 'CREATE TABLE CUSTOMER (\n CUST_NO CUSTNO NOT NULL,\n CUSTOMER VARCHAR(25) NOT NULL,\n CONTACT_FIRST "FIRSTNAME",\n CONTACT_LAST "LASTNAME",\n PHONE_NO PHONENUMBER,\n ADDRESS_LINE1 ADDRESSLINE,\n ADDRESS_LINE2 ADDRESSLINE,\n CITY VARCHAR(25),\n STATE_PROVINCE VARCHAR(15),\n COUNTRY COUNTRYNAME,\n POSTAL_CODE VARCHAR(12),\n ON_HOLD CHAR(1) DEFAULT NULL\n)', 5574 'CREATE TABLE PROJECT (\n PROJ_ID PROJNO NOT NULL,\n PROJ_NAME VARCHAR(20) NOT NULL,\n PROJ_DESC BLOB SUB_TYPE TEXT SEGMENT SIZE 800,\n TEAM_LEADER EMPNO,\n PRODUCT PRODTYPE\n)', 5575 'CREATE TABLE EMPLOYEE_PROJECT (\n EMP_NO EMPNO NOT NULL,\n PROJ_ID PROJNO NOT NULL\n)', 5576 'CREATE TABLE PROJ_DEPT_BUDGET (\n FISCAL_YEAR INTEGER NOT NULL,\n PROJ_ID PROJNO NOT NULL,\n DEPT_NO DEPTNO NOT NULL,\n QUART_HEAD_CNT INTEGER[4],\n PROJECTED_BUDGET BUDGET\n)', 5577 "CREATE TABLE SALARY_HISTORY (\n EMP_NO EMPNO NOT NULL,\n CHANGE_DATE TIMESTAMP DEFAULT 'NOW' NOT NULL,\n UPDATER_ID VARCHAR(20) NOT NULL,\n OLD_SALARY SALARY NOT NULL,\n PERCENT_CHANGE DOUBLE PRECISION DEFAULT 0 NOT NULL,\n NEW_SALARY COMPUTED BY (old_salary + old_salary * percent_change / 100)\n)", 5578 "CREATE TABLE SALES (\n PO_NUMBER PONUMBER NOT NULL,\n CUST_NO CUSTNO NOT NULL,\n SALES_REP EMPNO,\n ORDER_STATUS VARCHAR(7) DEFAULT 'new' NOT NULL,\n ORDER_DATE TIMESTAMP DEFAULT 'NOW' NOT NULL,\n SHIP_DATE TIMESTAMP,\n DATE_NEEDED TIMESTAMP,\n PAID CHAR(1) DEFAULT 'n',\n QTY_ORDERED INTEGER DEFAULT 1 NOT NULL,\n TOTAL_VALUE DECIMAL(9, 2) NOT NULL,\n DISCOUNT FLOAT DEFAULT 0 NOT NULL,\n ITEM_TYPE PRODTYPE,\n AGED COMPUTED BY (ship_date - order_date)\n)", 5579 'CREATE TABLE AR (\n C1 INTEGER,\n C2 INTEGER[4, 0:3, 2],\n C3 VARCHAR(15)[0:5, 2],\n C4 CHAR(5)[5],\n C5 TIMESTAMP[2],\n C6 TIME[2],\n C7 DECIMAL(10, 2)[2],\n C8 NUMERIC(10, 2)[2],\n C9 SMALLINT[2],\n C10 BIGINT[2],\n C11 FLOAT[2],\n C12 DOUBLE PRECISION[2],\n C13 DECIMAL(10, 1)[2],\n C14 DECIMAL(10, 5)[2],\n C15 DECIMAL(18, 5)[2],\n C16 BOOLEAN[3]\n)', 5580 'CREATE TABLE T2 (\n C1 SMALLINT,\n C2 INTEGER,\n C3 BIGINT,\n C4 CHAR(5),\n C5 VARCHAR(10),\n C6 DATE,\n C7 TIME,\n C8 TIMESTAMP,\n C9 BLOB SUB_TYPE TEXT SEGMENT SIZE 80,\n C10 NUMERIC(18, 2),\n C11 DECIMAL(18, 2),\n C12 FLOAT,\n C13 DOUBLE PRECISION,\n C14 NUMERIC(8, 4),\n C15 DECIMAL(8, 4),\n C16 BLOB SUB_TYPE BINARY SEGMENT SIZE 80,\n C17 BOOLEAN\n)', 5581 'CREATE TABLE T3 (\n C1 INTEGER,\n C2 CHAR(10) CHARACTER SET UTF8,\n C3 VARCHAR(10) CHARACTER SET UTF8,\n C4 BLOB SUB_TYPE TEXT SEGMENT SIZE 80 CHARACTER SET UTF8,\n C5 BLOB SUB_TYPE BINARY SEGMENT SIZE 80\n)', 5582 'CREATE TABLE T4 (\n C1 INTEGER,\n C_OCTETS CHAR(5) CHARACTER SET OCTETS,\n V_OCTETS VARCHAR(30) CHARACTER SET OCTETS,\n C_NONE CHAR(5),\n V_NONE VARCHAR(30),\n C_WIN1250 CHAR(5) CHARACTER SET WIN1250,\n V_WIN1250 VARCHAR(30) CHARACTER SET WIN1250,\n C_UTF8 CHAR(5) CHARACTER SET UTF8,\n V_UTF8 VARCHAR(30) CHARACTER SET UTF8\n)', 5583 'CREATE TABLE T5 (\n ID NUMERIC(10, 0) GENERATED BY DEFAULT AS IDENTITY,\n C1 VARCHAR(15),\n UQ BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 100)\n)', 'CREATE TABLE T (\n C1 INTEGER NOT NULL\n)']) 5584 else: 5585 self.assertListEqual(script, ['CREATE TABLE COUNTRY (\n COUNTRY COUNTRYNAME NOT NULL,\n CURRENCY VARCHAR(10) NOT NULL\n)', 5586 'CREATE TABLE JOB (\n JOB_CODE JOBCODE NOT NULL,\n JOB_GRADE JOBGRADE NOT NULL,\n JOB_COUNTRY COUNTRYNAME NOT NULL,\n JOB_TITLE VARCHAR(25) NOT NULL,\n MIN_SALARY SALARY NOT NULL,\n MAX_SALARY SALARY NOT NULL,\n JOB_REQUIREMENT BLOB SUB_TYPE TEXT SEGMENT SIZE 400,\n LANGUAGE_REQ VARCHAR(15)[5]\n)', 5587 "CREATE TABLE DEPARTMENT (\n DEPT_NO DEPTNO NOT NULL,\n DEPARTMENT VARCHAR(25) NOT NULL,\n HEAD_DEPT DEPTNO,\n MNGR_NO EMPNO,\n BUDGET BUDGET,\n LOCATION VARCHAR(15),\n PHONE_NO PHONENUMBER DEFAULT '555-1234'\n)", 5588 'CREATE TABLE EMPLOYEE (\n EMP_NO EMPNO NOT NULL,\n FIRST_NAME "FIRSTNAME" NOT NULL,\n LAST_NAME "LASTNAME" NOT NULL,\n PHONE_EXT VARCHAR(4),\n HIRE_DATE TIMESTAMP DEFAULT \'NOW\' NOT NULL,\n DEPT_NO DEPTNO NOT NULL,\n JOB_CODE JOBCODE NOT NULL,\n JOB_GRADE JOBGRADE NOT NULL,\n JOB_COUNTRY COUNTRYNAME NOT NULL,\n SALARY SALARY NOT NULL,\n FULL_NAME COMPUTED BY (last_name || \', \' || first_name)\n)', 5589 'CREATE TABLE CUSTOMER (\n CUST_NO CUSTNO NOT NULL,\n CUSTOMER VARCHAR(25) NOT NULL,\n CONTACT_FIRST "FIRSTNAME",\n CONTACT_LAST "LASTNAME",\n PHONE_NO PHONENUMBER,\n ADDRESS_LINE1 ADDRESSLINE,\n ADDRESS_LINE2 ADDRESSLINE,\n CITY VARCHAR(25),\n STATE_PROVINCE VARCHAR(15),\n COUNTRY COUNTRYNAME,\n POSTAL_CODE VARCHAR(12),\n ON_HOLD CHAR(1) DEFAULT NULL\n)', 5590 'CREATE TABLE T4 (\n C1 INTEGER,\n C_OCTETS CHAR(5) CHARACTER SET OCTETS,\n V_OCTETS VARCHAR(30) CHARACTER SET OCTETS,\n C_NONE CHAR(5),\n V_NONE VARCHAR(30),\n C_WIN1250 CHAR(5) CHARACTER SET WIN1250,\n V_WIN1250 VARCHAR(30) CHARACTER SET WIN1250,\n C_UTF8 CHAR(5) CHARACTER SET UTF8,\n V_UTF8 VARCHAR(30) CHARACTER SET UTF8\n)', 5591 'CREATE TABLE PROJECT (\n PROJ_ID PROJNO NOT NULL,\n PROJ_NAME VARCHAR(20) NOT NULL,\n PROJ_DESC BLOB SUB_TYPE TEXT SEGMENT SIZE 800,\n TEAM_LEADER EMPNO,\n PRODUCT PRODTYPE\n)', 5592 'CREATE TABLE EMPLOYEE_PROJECT (\n EMP_NO EMPNO NOT NULL,\n PROJ_ID PROJNO NOT NULL\n)', 5593 'CREATE TABLE PROJ_DEPT_BUDGET (\n FISCAL_YEAR INTEGER NOT NULL,\n PROJ_ID PROJNO NOT NULL,\n DEPT_NO DEPTNO NOT NULL,\n QUART_HEAD_CNT INTEGER[4],\n PROJECTED_BUDGET BUDGET\n)', 5594 "CREATE TABLE SALARY_HISTORY (\n EMP_NO EMPNO NOT NULL,\n CHANGE_DATE TIMESTAMP DEFAULT 'NOW' NOT NULL,\n UPDATER_ID VARCHAR(20) NOT NULL,\n OLD_SALARY SALARY NOT NULL,\n PERCENT_CHANGE DOUBLE PRECISION DEFAULT 0 NOT NULL,\n NEW_SALARY COMPUTED BY (old_salary + old_salary * percent_change / 100)\n)", 5595 "CREATE TABLE SALES (\n PO_NUMBER PONUMBER NOT NULL,\n CUST_NO CUSTNO NOT NULL,\n SALES_REP EMPNO,\n ORDER_STATUS VARCHAR(7) DEFAULT 'new' NOT NULL,\n ORDER_DATE TIMESTAMP DEFAULT 'NOW' NOT NULL,\n SHIP_DATE TIMESTAMP,\n DATE_NEEDED TIMESTAMP,\n PAID CHAR(1) DEFAULT 'n',\n QTY_ORDERED INTEGER DEFAULT 1 NOT NULL,\n TOTAL_VALUE DECIMAL(9, 2) NOT NULL,\n DISCOUNT FLOAT DEFAULT 0 NOT NULL,\n ITEM_TYPE PRODTYPE,\n AGED COMPUTED BY (ship_date - order_date)\n)", 5596 'CREATE TABLE T3 (\n C1 INTEGER,\n C2 CHAR(10) CHARACTER SET UTF8,\n C3 VARCHAR(10) CHARACTER SET UTF8,\n C4 BLOB SUB_TYPE TEXT SEGMENT SIZE 80 CHARACTER SET UTF8,\n C5 BLOB SUB_TYPE BINARY SEGMENT SIZE 80\n)', 5597 'CREATE TABLE T2 (\n C1 SMALLINT,\n C2 INTEGER,\n C3 BIGINT,\n C4 CHAR(5),\n C5 VARCHAR(10),\n C6 DATE,\n C7 TIME,\n C8 TIMESTAMP,\n C9 BLOB SUB_TYPE TEXT SEGMENT SIZE 80,\n C10 NUMERIC(18, 2),\n C11 DECIMAL(18, 2),\n C12 FLOAT,\n C13 DOUBLE PRECISION,\n C14 NUMERIC(8, 4),\n C15 DECIMAL(8, 4),\n C16 BLOB SUB_TYPE BINARY SEGMENT SIZE 80\n)', 5598 'CREATE TABLE AR (\n C1 INTEGER,\n C2 INTEGER[4, 0:3, 2],\n C3 VARCHAR(15)[0:5, 2],\n C4 CHAR(5)[5],\n C5 TIMESTAMP[2],\n C6 TIME[2],\n C7 DECIMAL(10, 2)[2],\n C8 NUMERIC(10, 2)[2],\n C9 SMALLINT[2],\n C10 BIGINT[2],\n C11 FLOAT[2],\n C12 DOUBLE PRECISION[2],\n C13 DECIMAL(10, 1)[2],\n C14 DECIMAL(10, 5)[2],\n C15 DECIMAL(18, 5)[2]\n)', 5599 'CREATE TABLE T (\n C1 INTEGER NOT NULL\n)']) 5600 script = s.get_metadata_ddl([sm.SCRIPT_PRIMARY_KEYS]) 5601 if self.version == FB30: 5602 self.assertListEqual(script, ['ALTER TABLE COUNTRY ADD PRIMARY KEY (COUNTRY)', 5603 'ALTER TABLE JOB ADD PRIMARY KEY (JOB_CODE,JOB_GRADE,JOB_COUNTRY)', 5604 'ALTER TABLE DEPARTMENT ADD PRIMARY KEY (DEPT_NO)', 5605 'ALTER TABLE EMPLOYEE ADD PRIMARY KEY (EMP_NO)', 5606 'ALTER TABLE PROJECT ADD PRIMARY KEY (PROJ_ID)', 5607 'ALTER TABLE EMPLOYEE_PROJECT ADD PRIMARY KEY (EMP_NO,PROJ_ID)', 5608 'ALTER TABLE PROJ_DEPT_BUDGET ADD PRIMARY KEY (FISCAL_YEAR,PROJ_ID,DEPT_NO)', 5609 'ALTER TABLE SALARY_HISTORY ADD PRIMARY KEY (EMP_NO,CHANGE_DATE,UPDATER_ID)', 5610 'ALTER TABLE CUSTOMER ADD PRIMARY KEY (CUST_NO)', 5611 'ALTER TABLE SALES ADD PRIMARY KEY (PO_NUMBER)', 5612 'ALTER TABLE T5 ADD PRIMARY KEY (ID)', 5613 'ALTER TABLE T ADD PRIMARY KEY (C1)'],) 5614 else: 5615 self.assertListEqual(script, ['ALTER TABLE COUNTRY ADD PRIMARY KEY (COUNTRY)', 5616 'ALTER TABLE JOB ADD PRIMARY KEY (JOB_CODE,JOB_GRADE,JOB_COUNTRY)', 5617 'ALTER TABLE DEPARTMENT ADD PRIMARY KEY (DEPT_NO)', 5618 'ALTER TABLE EMPLOYEE ADD PRIMARY KEY (EMP_NO)', 5619 'ALTER TABLE PROJECT ADD PRIMARY KEY (PROJ_ID)', 5620 'ALTER TABLE EMPLOYEE_PROJECT ADD PRIMARY KEY (EMP_NO,PROJ_ID)', 5621 'ALTER TABLE PROJ_DEPT_BUDGET ADD PRIMARY KEY (FISCAL_YEAR,PROJ_ID,DEPT_NO)', 5622 'ALTER TABLE SALARY_HISTORY ADD PRIMARY KEY (EMP_NO,CHANGE_DATE,UPDATER_ID)', 5623 'ALTER TABLE CUSTOMER ADD PRIMARY KEY (CUST_NO)', 5624 'ALTER TABLE SALES ADD PRIMARY KEY (PO_NUMBER)', 5625 'ALTER TABLE T ADD PRIMARY KEY (C1)'],) 5626 script = s.get_metadata_ddl([sm.SCRIPT_UNIQUE_CONSTRAINTS]) 5627 self.assertListEqual(script, ['ALTER TABLE DEPARTMENT ADD UNIQUE (DEPARTMENT)', 5628 'ALTER TABLE PROJECT ADD UNIQUE (PROJ_NAME)']) 5629 script = s.get_metadata_ddl([sm.SCRIPT_CHECK_CONSTRAINTS]) 5630 #self.assertListEqual(script, ['ALTER TABLE JOB ADD CHECK (min_salary < max_salary)', 5631 #'ALTER TABLE EMPLOYEE ADD CHECK ( salary >= (SELECT min_salary FROM job WHERE\n job.job_code = employee.job_code AND\n job.job_grade = employee.job_grade AND\n job.job_country = employee.job_country) AND\n salary <= (SELECT max_salary FROM job WHERE\n job.job_code = employee.job_code AND\n job.job_grade = employee.job_grade AND\n job.job_country = employee.job_country))', 5632 #"ALTER TABLE CUSTOMER ADD CHECK (on_hold IS NULL OR on_hold = '*')", 5633 #'ALTER TABLE PROJ_DEPT_BUDGET ADD CHECK (FISCAL_YEAR >= 1993)', 5634 #'ALTER TABLE SALARY_HISTORY ADD CHECK (percent_change between -50 and 50)', 5635 #'ALTER TABLE SALES ADD CHECK (total_value >= 0)', 5636 #'ALTER TABLE SALES ADD CHECK (ship_date >= order_date OR ship_date IS NULL)', 5637 #"ALTER TABLE SALES ADD CHECK (NOT (order_status = 'shipped' AND\n EXISTS (SELECT on_hold FROM customer\n WHERE customer.cust_no = sales.cust_no\n AND customer.on_hold = '*')))", 5638 #'ALTER TABLE SALES ADD CHECK (date_needed > order_date OR date_needed IS NULL)', 5639 #"ALTER TABLE SALES ADD CHECK (paid in ('y', 'n'))", 5640 #"ALTER TABLE SALES ADD CHECK (NOT (order_status = 'shipped' AND ship_date IS NULL))", 5641 #"ALTER TABLE SALES ADD CHECK (order_status in\n ('new', 'open', 'shipped', 'waiting'))", 5642 #'ALTER TABLE SALES ADD CHECK (discount >= 0 AND discount <= 1)', 5643 #'ALTER TABLE SALES ADD CHECK (qty_ordered >= 1)']) 5644 script = s.get_metadata_ddl([sm.SCRIPT_FOREIGN_CONSTRAINTS]) 5645 self.assertListEqual(script, ['ALTER TABLE JOB ADD FOREIGN KEY (JOB_COUNTRY)\n REFERENCES COUNTRY (COUNTRY)', 5646 'ALTER TABLE DEPARTMENT ADD FOREIGN KEY (HEAD_DEPT)\n REFERENCES DEPARTMENT (DEPT_NO)', 5647 'ALTER TABLE DEPARTMENT ADD FOREIGN KEY (MNGR_NO)\n REFERENCES EMPLOYEE (EMP_NO)', 5648 'ALTER TABLE EMPLOYEE ADD FOREIGN KEY (DEPT_NO)\n REFERENCES DEPARTMENT (DEPT_NO)', 5649 'ALTER TABLE EMPLOYEE ADD FOREIGN KEY (JOB_CODE,JOB_GRADE,JOB_COUNTRY)\n REFERENCES JOB (JOB_CODE,JOB_GRADE,JOB_COUNTRY)', 5650 'ALTER TABLE CUSTOMER ADD FOREIGN KEY (COUNTRY)\n REFERENCES COUNTRY (COUNTRY)', 5651 'ALTER TABLE PROJECT ADD FOREIGN KEY (TEAM_LEADER)\n REFERENCES EMPLOYEE (EMP_NO)', 5652 'ALTER TABLE EMPLOYEE_PROJECT ADD FOREIGN KEY (EMP_NO)\n REFERENCES EMPLOYEE (EMP_NO)', 5653 'ALTER TABLE EMPLOYEE_PROJECT ADD FOREIGN KEY (PROJ_ID)\n REFERENCES PROJECT (PROJ_ID)', 5654 'ALTER TABLE PROJ_DEPT_BUDGET ADD FOREIGN KEY (DEPT_NO)\n REFERENCES DEPARTMENT (DEPT_NO)', 5655 'ALTER TABLE PROJ_DEPT_BUDGET ADD FOREIGN KEY (PROJ_ID)\n REFERENCES PROJECT (PROJ_ID)', 5656 'ALTER TABLE SALARY_HISTORY ADD FOREIGN KEY (EMP_NO)\n REFERENCES EMPLOYEE (EMP_NO)', 5657 'ALTER TABLE SALES ADD FOREIGN KEY (CUST_NO)\n REFERENCES CUSTOMER (CUST_NO)', 5658 'ALTER TABLE SALES ADD FOREIGN KEY (SALES_REP)\n REFERENCES EMPLOYEE (EMP_NO)']) 5659 script = s.get_metadata_ddl([sm.SCRIPT_INDICES]) 5660 self.assertListEqual(script, ['CREATE ASCENDING INDEX MINSALX ON JOB (JOB_COUNTRY,MIN_SALARY)', 5661 'CREATE DESCENDING INDEX MAXSALX ON JOB (JOB_COUNTRY,MAX_SALARY)', 5662 'CREATE DESCENDING INDEX BUDGETX ON DEPARTMENT (BUDGET)', 5663 'CREATE ASCENDING INDEX NAMEX ON EMPLOYEE (LAST_NAME,FIRST_NAME)', 5664 'CREATE ASCENDING INDEX CUSTNAMEX ON CUSTOMER (CUSTOMER)', 5665 'CREATE ASCENDING INDEX CUSTREGION ON CUSTOMER (COUNTRY,CITY)', 5666 'CREATE UNIQUE ASCENDING INDEX PRODTYPEX ON PROJECT (PRODUCT,PROJ_NAME)', 5667 'CREATE ASCENDING INDEX UPDATERX ON SALARY_HISTORY (UPDATER_ID)', 5668 'CREATE DESCENDING INDEX CHANGEX ON SALARY_HISTORY (CHANGE_DATE)', 5669 'CREATE ASCENDING INDEX NEEDX ON SALES (DATE_NEEDED)', 5670 'CREATE ASCENDING INDEX SALESTATX ON SALES (ORDER_STATUS,PAID)', 5671 'CREATE DESCENDING INDEX QTYX ON SALES (ITEM_TYPE,QTY_ORDERED)']) 5672 script = s.get_metadata_ddl([sm.SCRIPT_VIEWS]) 5673 self.assertListEqual(script, ['CREATE VIEW PHONE_LIST (EMP_NO,FIRST_NAME,LAST_NAME,PHONE_EXT,LOCATION,PHONE_NO)\n AS\n SELECT\n emp_no, first_name, last_name, phone_ext, location, phone_no\n FROM employee, department\n WHERE employee.dept_no = department.dept_no']) 5674 if self.version == FB30: 5675 script = s.get_metadata_ddl([sm.SCRIPT_PACKAGE_BODIES]) 5676 self.assertListEqual(script, ['CREATE PACKAGE BODY TEST\nAS\nBEGIN\n FUNCTION F1(I INT) RETURNS INT; -- private function\n\n PROCEDURE P1(I INT) RETURNS (O INT)\n AS\n BEGIN\n END\n\n FUNCTION F1(I INT) RETURNS INT\n AS\n BEGIN\n RETURN F(I)+10;\n END\n\n FUNCTION F(X INT) RETURNS INT\n AS\n BEGIN\n RETURN X+1;\n END\nEND', 'CREATE PACKAGE BODY TEST2\nAS\nBEGIN\n FUNCTION F3(X INT) RETURNS INT\n AS\n BEGIN\n RETURN TEST.F(X)+100+FN();\n END\nEND']) 5677 script = s.get_metadata_ddl([sm.SCRIPT_FUNCTION_BODIES]) 5678 self.assertListEqual(script, ['ALTER FUNCTION F2 (X INTEGER)\nRETURNS INTEGER\nAS\nBEGIN\n RETURN X+1;\nEND', 5679 'ALTER FUNCTION FX (\n F TYPE OF "FIRSTNAME",\n L TYPE OF COLUMN CUSTOMER.CONTACT_LAST\n)\nRETURNS VARCHAR(35)\nAS\nBEGIN\n RETURN L || \', \' || F;\nEND', 5680 'ALTER FUNCTION FN\nRETURNS INTEGER\nAS\nBEGIN\n RETURN 0;\nEND']) 5681 script = s.get_metadata_ddl([sm.SCRIPT_PROCEDURE_BODIES]) 5682 self.assertListEqual(script, ['ALTER PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT)\nRETURNS (PROJ_ID CHAR(5))\nAS\nBEGIN\n\tFOR SELECT proj_id\n\t\tFROM employee_project\n\t\tWHERE emp_no = :emp_no\n\t\tINTO :proj_id\n\tDO\n\t\tSUSPEND;\nEND', 'ALTER PROCEDURE ADD_EMP_PROJ (\n EMP_NO SMALLINT,\n PROJ_ID CHAR(5)\n)\nAS\nBEGIN\n\tBEGIN\n\tINSERT INTO employee_project (emp_no, proj_id) VALUES (:emp_no, :proj_id);\n\tWHEN SQLCODE -530 DO\n\t\tEXCEPTION unknown_emp_id;\n\tEND\n\tSUSPEND;\nEND', 5683 'ALTER PROCEDURE SUB_TOT_BUDGET (HEAD_DEPT CHAR(3))\nRETURNS (\n TOT_BUDGET DECIMAL(12, 2),\n AVG_BUDGET DECIMAL(12, 2),\n MIN_BUDGET DECIMAL(12, 2),\n MAX_BUDGET DECIMAL(12, 2)\n)\nAS\nBEGIN\n\tSELECT SUM(budget), AVG(budget), MIN(budget), MAX(budget)\n\t\tFROM department\n\t\tWHERE head_dept = :head_dept\n\t\tINTO :tot_budget, :avg_budget, :min_budget, :max_budget;\n\tSUSPEND;\nEND', 5684 "ALTER PROCEDURE DELETE_EMPLOYEE (EMP_NUM INTEGER)\nAS\nDECLARE VARIABLE any_sales INTEGER;\nBEGIN\n\tany_sales = 0;\n\n\t/*\n\t *\tIf there are any sales records referencing this employee,\n\t *\tcan't delete the employee until the sales are re-assigned\n\t *\tto another employee or changed to NULL.\n\t */\n\tSELECT count(po_number)\n\tFROM sales\n\tWHERE sales_rep = :emp_num\n\tINTO :any_sales;\n\n\tIF (any_sales > 0) THEN\n\tBEGIN\n\t\tEXCEPTION reassign_sales;\n\t\tSUSPEND;\n\tEND\n\n\t/*\n\t *\tIf the employee is a manager, update the department.\n\t */\n\tUPDATE department\n\tSET mngr_no = NULL\n\tWHERE mngr_no = :emp_num;\n\n\t/*\n\t *\tIf the employee is a project leader, update project.\n\t */\n\tUPDATE project\n\tSET team_leader = NULL\n\tWHERE team_leader = :emp_num;\n\n\t/*\n\t *\tDelete the employee from any projects.\n\t */\n\tDELETE FROM employee_project\n\tWHERE emp_no = :emp_num;\n\n\t/*\n\t *\tDelete old salary records.\n\t */\n\tDELETE FROM salary_history\n\tWHERE emp_no = :emp_num;\n\n\t/*\n\t *\tDelete the employee.\n\t */\n\tDELETE FROM employee\n\tWHERE emp_no = :emp_num;\n\n\tSUSPEND;\nEND", 5685 'ALTER PROCEDURE DEPT_BUDGET (DNO CHAR(3))\nRETURNS (TOT DECIMAL(12, 2))\nAS\nDECLARE VARIABLE sumb DECIMAL(12, 2);\n\tDECLARE VARIABLE rdno CHAR(3);\n\tDECLARE VARIABLE cnt INTEGER;\nBEGIN\n\ttot = 0;\n\n\tSELECT budget FROM department WHERE dept_no = :dno INTO :tot;\n\n\tSELECT count(budget) FROM department WHERE head_dept = :dno INTO :cnt;\n\n\tIF (cnt = 0) THEN\n\t\tSUSPEND;\n\n\tFOR SELECT dept_no\n\t\tFROM department\n\t\tWHERE head_dept = :dno\n\t\tINTO :rdno\n\tDO\n\t\tBEGIN\n\t\t\tEXECUTE PROCEDURE dept_budget :rdno RETURNING_VALUES :sumb;\n\t\t\ttot = tot + sumb;\n\t\tEND\n\n\tSUSPEND;\nEND', 5686 "ALTER PROCEDURE ORG_CHART\nRETURNS (\n HEAD_DEPT CHAR(25),\n DEPARTMENT CHAR(25),\n MNGR_NAME CHAR(20),\n TITLE CHAR(5),\n EMP_CNT INTEGER\n)\nAS\nDECLARE VARIABLE mngr_no INTEGER;\n\tDECLARE VARIABLE dno CHAR(3);\nBEGIN\n\tFOR SELECT h.department, d.department, d.mngr_no, d.dept_no\n\t\tFROM department d\n\t\tLEFT OUTER JOIN department h ON d.head_dept = h.dept_no\n\t\tORDER BY d.dept_no\n\t\tINTO :head_dept, :department, :mngr_no, :dno\n\tDO\n\tBEGIN\n\t\tIF (:mngr_no IS NULL) THEN\n\t\tBEGIN\n\t\t\tmngr_name = '--TBH--';\n\t\t\ttitle = '';\n\t\tEND\n\n\t\tELSE\n\t\t\tSELECT full_name, job_code\n\t\t\tFROM employee\n\t\t\tWHERE emp_no = :mngr_no\n\t\t\tINTO :mngr_name, :title;\n\n\t\tSELECT COUNT(emp_no)\n\t\tFROM employee\n\t\tWHERE dept_no = :dno\n\t\tINTO :emp_cnt;\n\n\t\tSUSPEND;\n\tEND\nEND", 5687 "ALTER PROCEDURE MAIL_LABEL (CUST_NO INTEGER)\nRETURNS (\n LINE1 CHAR(40),\n LINE2 CHAR(40),\n LINE3 CHAR(40),\n LINE4 CHAR(40),\n LINE5 CHAR(40),\n LINE6 CHAR(40)\n)\nAS\nDECLARE VARIABLE customer\tVARCHAR(25);\n\tDECLARE VARIABLE first_name\t\tVARCHAR(15);\n\tDECLARE VARIABLE last_name\t\tVARCHAR(20);\n\tDECLARE VARIABLE addr1\t\tVARCHAR(30);\n\tDECLARE VARIABLE addr2\t\tVARCHAR(30);\n\tDECLARE VARIABLE city\t\tVARCHAR(25);\n\tDECLARE VARIABLE state\t\tVARCHAR(15);\n\tDECLARE VARIABLE country\tVARCHAR(15);\n\tDECLARE VARIABLE postcode\tVARCHAR(12);\n\tDECLARE VARIABLE cnt\t\tINTEGER;\nBEGIN\n\tline1 = '';\n\tline2 = '';\n\tline3 = '';\n\tline4 = '';\n\tline5 = '';\n\tline6 = '';\n\n\tSELECT customer, contact_first, contact_last, address_line1,\n\t\taddress_line2, city, state_province, country, postal_code\n\tFROM CUSTOMER\n\tWHERE cust_no = :cust_no\n\tINTO :customer, :first_name, :last_name, :addr1, :addr2,\n\t\t:city, :state, :country, :postcode;\n\n\tIF (customer IS NOT NULL) THEN\n\t\tline1 = customer;\n\tIF (first_name IS NOT NULL) THEN\n\t\tline2 = first_name || ' ' || last_name;\n\tELSE\n\t\tline2 = last_name;\n\tIF (addr1 IS NOT NULL) THEN\n\t\tline3 = addr1;\n\tIF (addr2 IS NOT NULL) THEN\n\t\tline4 = addr2;\n\n\tIF (country = 'USA') THEN\n\tBEGIN\n\t\tIF (city IS NOT NULL) THEN\n\t\t\tline5 = city || ', ' || state || ' ' || postcode;\n\t\tELSE\n\t\t\tline5 = state || ' ' || postcode;\n\tEND\n\tELSE\n\tBEGIN\n\t\tIF (city IS NOT NULL) THEN\n\t\t\tline5 = city || ', ' || state;\n\t\tELSE\n\t\t\tline5 = state;\n\t\tline6 = country || ' ' || postcode;\n\tEND\n\n\tSUSPEND;\nEND", 5688 "ALTER PROCEDURE SHIP_ORDER (PO_NUM CHAR(8))\nAS\nDECLARE VARIABLE ord_stat CHAR(7);\n\tDECLARE VARIABLE hold_stat CHAR(1);\n\tDECLARE VARIABLE cust_no INTEGER;\n\tDECLARE VARIABLE any_po CHAR(8);\nBEGIN\n\tSELECT s.order_status, c.on_hold, c.cust_no\n\tFROM sales s, customer c\n\tWHERE po_number = :po_num\n\tAND s.cust_no = c.cust_no\n\tINTO :ord_stat, :hold_stat, :cust_no;\n\n\t/* This purchase order has been already shipped. */\n\tIF (ord_stat = 'shipped') THEN\n\tBEGIN\n\t\tEXCEPTION order_already_shipped;\n\t\tSUSPEND;\n\tEND\n\n\t/*\tCustomer is on hold. */\n\tELSE IF (hold_stat = '*') THEN\n\tBEGIN\n\t\tEXCEPTION customer_on_hold;\n\t\tSUSPEND;\n\tEND\n\n\t/*\n\t *\tIf there is an unpaid balance on orders shipped over 2 months ago,\n\t *\tput the customer on hold.\n\t */\n\tFOR SELECT po_number\n\t\tFROM sales\n\t\tWHERE cust_no = :cust_no\n\t\tAND order_status = 'shipped'\n\t\tAND paid = 'n'\n\t\tAND ship_date < CAST('NOW' AS TIMESTAMP) - 60\n\t\tINTO :any_po\n\tDO\n\tBEGIN\n\t\tEXCEPTION customer_check;\n\n\t\tUPDATE customer\n\t\tSET on_hold = '*'\n\t\tWHERE cust_no = :cust_no;\n\n\t\tSUSPEND;\n\tEND\n\n\t/*\n\t *\tShip the order.\n\t */\n\tUPDATE sales\n\tSET order_status = 'shipped', ship_date = 'NOW'\n\tWHERE po_number = :po_num;\n\n\tSUSPEND;\nEND", 5689 "ALTER PROCEDURE SHOW_LANGS (\n CODE VARCHAR(5),\n GRADE SMALLINT,\n CTY VARCHAR(15)\n)\nRETURNS (LANGUAGES VARCHAR(15))\nAS\nDECLARE VARIABLE i INTEGER;\nBEGIN\n i = 1;\n WHILE (i <= 5) DO\n BEGIN\n SELECT language_req[:i] FROM joB\n WHERE ((job_code = :code) AND (job_grade = :grade) AND (job_country = :cty)\n AND (language_req IS NOT NULL))\n INTO :languages;\n IF (languages = ' ') THEN /* Prints 'NULL' instead of blanks */\n languages = 'NULL'; \n i = i +1;\n SUSPEND;\n END\nEND", 5690 "ALTER PROCEDURE ALL_LANGS\nRETURNS (\n CODE VARCHAR(5),\n GRADE VARCHAR(5),\n COUNTRY VARCHAR(15),\n LANG VARCHAR(15)\n)\nAS\nBEGIN\n\tFOR SELECT job_code, job_grade, job_country FROM job \n\t\tINTO :code, :grade, :country\n\n\tDO\n\tBEGIN\n\t FOR SELECT languages FROM show_langs \n \t\t (:code, :grade, :country) INTO :lang DO\n\t SUSPEND;\n\t /* Put nice separators between rows */\n\t code = '=====';\n\t grade = '=====';\n\t country = '===============';\n\t lang = '==============';\n\t SUSPEND;\n\tEND\n END"]) 5691 script = s.get_metadata_ddl([sm.SCRIPT_TRIGGERS]) 5692 if self.version == FB30: 5693 self.assertListEqual(script, ['CREATE TRIGGER SET_EMP_NO FOR EMPLOYEE ACTIVE\nBEFORE INSERT POSITION 0\nAS\nBEGIN\n if (new.emp_no is null) then\n new.emp_no = gen_id(emp_no_gen, 1);\nEND', 5694 "CREATE TRIGGER SAVE_SALARY_CHANGE FOR EMPLOYEE ACTIVE\nAFTER UPDATE POSITION 0\nAS\nBEGIN\n IF (old.salary <> new.salary) THEN\n INSERT INTO salary_history\n (emp_no, change_date, updater_id, old_salary, percent_change)\n VALUES (\n old.emp_no,\n 'NOW',\n user,\n old.salary,\n (new.salary - old.salary) * 100 / old.salary);\nEND", 5695 'CREATE TRIGGER SET_CUST_NO FOR CUSTOMER ACTIVE\nBEFORE INSERT POSITION 0\nAS\nBEGIN\n if (new.cust_no is null) then\n new.cust_no = gen_id(cust_no_gen, 1);\nEND', 5696 "CREATE TRIGGER POST_NEW_ORDER FOR SALES ACTIVE\nAFTER INSERT POSITION 0\nAS\nBEGIN\n POST_EVENT 'new_order';\nEND", 5697 'CREATE TRIGGER TR_CONNECT ACTIVE\nON CONNECT POSITION 0\nAS \nBEGIN \n /* enter trigger code here */ \nEND', 5698 'CREATE TRIGGER TR_MULTI FOR COUNTRY ACTIVE\nAFTER INSERT OR UPDATE OR DELETE POSITION 0\nAS \nBEGIN \n /* enter trigger code here */ \nEND']) 5699 else: 5700 self.assertListEqual(script, ['CREATE TRIGGER SET_EMP_NO FOR EMPLOYEE ACTIVE\nBEFORE INSERT POSITION 0\nAS\nBEGIN\n if (new.emp_no is null) then\n new.emp_no = gen_id(emp_no_gen, 1);\nEND', 5701 "CREATE TRIGGER SAVE_SALARY_CHANGE FOR EMPLOYEE ACTIVE\nAFTER UPDATE POSITION 0\nAS\nBEGIN\n IF (old.salary <> new.salary) THEN\n INSERT INTO salary_history\n (emp_no, change_date, updater_id, old_salary, percent_change)\n VALUES (\n old.emp_no,\n 'NOW',\n user,\n old.salary,\n (new.salary - old.salary) * 100 / old.salary);\nEND", 5702 'CREATE TRIGGER SET_CUST_NO FOR CUSTOMER ACTIVE\nBEFORE INSERT POSITION 0\nAS\nBEGIN\n if (new.cust_no is null) then\n new.cust_no = gen_id(cust_no_gen, 1);\nEND', 5703 "CREATE TRIGGER POST_NEW_ORDER FOR SALES ACTIVE\nAFTER INSERT POSITION 0\nAS\nBEGIN\n POST_EVENT 'new_order';\nEND", 5704 'CREATE TRIGGER TR_MULTI FOR COUNTRY ACTIVE\nAFTER INSERT OR UPDATE OR DELETE POSITION 0\nAS \nBEGIN \n /* enter trigger code here */ \nEND', 5705 'CREATE TRIGGER TR_CONNECT ACTIVE\nON CONNECT POSITION 0\nAS \nBEGIN \n /* enter trigger code here */ \nEND']) 5706 script = s.get_metadata_ddl([sm.SCRIPT_ROLES]) 5707 self.assertListEqual(script, ['CREATE ROLE TEST_ROLE']) 5708 script = s.get_metadata_ddl([sm.SCRIPT_GRANTS]) 5709 self.assertListEqual(script, ['GRANT SELECT ON COUNTRY TO PUBLIC WITH GRANT OPTION', 5710 'GRANT INSERT ON COUNTRY TO PUBLIC WITH GRANT OPTION', 5711 'GRANT UPDATE ON COUNTRY TO PUBLIC WITH GRANT OPTION', 5712 'GRANT DELETE ON COUNTRY TO PUBLIC WITH GRANT OPTION', 5713 'GRANT REFERENCES ON COUNTRY TO PUBLIC WITH GRANT OPTION', 5714 'GRANT SELECT ON JOB TO PUBLIC WITH GRANT OPTION', 5715 'GRANT INSERT ON JOB TO PUBLIC WITH GRANT OPTION', 5716 'GRANT UPDATE ON JOB TO PUBLIC WITH GRANT OPTION', 5717 'GRANT DELETE ON JOB TO PUBLIC WITH GRANT OPTION', 5718 'GRANT REFERENCES ON JOB TO PUBLIC WITH GRANT OPTION', 5719 'GRANT SELECT ON DEPARTMENT TO PUBLIC WITH GRANT OPTION', 5720 'GRANT INSERT ON DEPARTMENT TO PUBLIC WITH GRANT OPTION', 5721 'GRANT UPDATE ON DEPARTMENT TO PUBLIC WITH GRANT OPTION', 5722 'GRANT DELETE ON DEPARTMENT TO PUBLIC WITH GRANT OPTION', 5723 'GRANT REFERENCES ON DEPARTMENT TO PUBLIC WITH GRANT OPTION', 5724 'GRANT SELECT ON EMPLOYEE TO PUBLIC WITH GRANT OPTION', 5725 'GRANT INSERT ON EMPLOYEE TO PUBLIC WITH GRANT OPTION', 5726 'GRANT UPDATE ON EMPLOYEE TO PUBLIC WITH GRANT OPTION', 5727 'GRANT DELETE ON EMPLOYEE TO PUBLIC WITH GRANT OPTION', 5728 'GRANT REFERENCES ON EMPLOYEE TO PUBLIC WITH GRANT OPTION', 5729 'GRANT SELECT ON PHONE_LIST TO PUBLIC WITH GRANT OPTION', 5730 'GRANT INSERT ON PHONE_LIST TO PUBLIC WITH GRANT OPTION', 5731 'GRANT UPDATE ON PHONE_LIST TO PUBLIC WITH GRANT OPTION', 5732 'GRANT DELETE ON PHONE_LIST TO PUBLIC WITH GRANT OPTION', 5733 'GRANT REFERENCES ON PHONE_LIST TO PUBLIC WITH GRANT OPTION', 5734 'GRANT SELECT ON PROJECT TO PUBLIC WITH GRANT OPTION', 5735 'GRANT INSERT ON PROJECT TO PUBLIC WITH GRANT OPTION', 5736 'GRANT UPDATE ON PROJECT TO PUBLIC WITH GRANT OPTION', 5737 'GRANT DELETE ON PROJECT TO PUBLIC WITH GRANT OPTION', 5738 'GRANT REFERENCES ON PROJECT TO PUBLIC WITH GRANT OPTION', 5739 'GRANT SELECT ON EMPLOYEE_PROJECT TO PUBLIC WITH GRANT OPTION', 5740 'GRANT INSERT ON EMPLOYEE_PROJECT TO PUBLIC WITH GRANT OPTION', 5741 'GRANT UPDATE ON EMPLOYEE_PROJECT TO PUBLIC WITH GRANT OPTION', 5742 'GRANT DELETE ON EMPLOYEE_PROJECT TO PUBLIC WITH GRANT OPTION', 5743 'GRANT REFERENCES ON EMPLOYEE_PROJECT TO PUBLIC WITH GRANT OPTION', 5744 'GRANT SELECT ON PROJ_DEPT_BUDGET TO PUBLIC WITH GRANT OPTION', 5745 'GRANT INSERT ON PROJ_DEPT_BUDGET TO PUBLIC WITH GRANT OPTION', 5746 'GRANT UPDATE ON PROJ_DEPT_BUDGET TO PUBLIC WITH GRANT OPTION', 5747 'GRANT DELETE ON PROJ_DEPT_BUDGET TO PUBLIC WITH GRANT OPTION', 5748 'GRANT REFERENCES ON PROJ_DEPT_BUDGET TO PUBLIC WITH GRANT OPTION', 5749 'GRANT SELECT ON SALARY_HISTORY TO PUBLIC WITH GRANT OPTION', 5750 'GRANT INSERT ON SALARY_HISTORY TO PUBLIC WITH GRANT OPTION', 5751 'GRANT UPDATE ON SALARY_HISTORY TO PUBLIC WITH GRANT OPTION', 5752 'GRANT DELETE ON SALARY_HISTORY TO PUBLIC WITH GRANT OPTION', 5753 'GRANT REFERENCES ON SALARY_HISTORY TO PUBLIC WITH GRANT OPTION', 5754 'GRANT SELECT ON CUSTOMER TO PUBLIC WITH GRANT OPTION', 5755 'GRANT INSERT ON CUSTOMER TO PUBLIC WITH GRANT OPTION', 5756 'GRANT UPDATE ON CUSTOMER TO PUBLIC WITH GRANT OPTION', 5757 'GRANT DELETE ON CUSTOMER TO PUBLIC WITH GRANT OPTION', 5758 'GRANT REFERENCES ON CUSTOMER TO PUBLIC WITH GRANT OPTION', 5759 'GRANT SELECT ON SALES TO PUBLIC WITH GRANT OPTION', 5760 'GRANT INSERT ON SALES TO PUBLIC WITH GRANT OPTION', 5761 'GRANT UPDATE ON SALES TO PUBLIC WITH GRANT OPTION', 5762 'GRANT DELETE ON SALES TO PUBLIC WITH GRANT OPTION', 5763 'GRANT REFERENCES ON SALES TO PUBLIC WITH GRANT OPTION', 5764 'GRANT EXECUTE ON PROCEDURE GET_EMP_PROJ TO PUBLIC WITH GRANT OPTION', 5765 'GRANT EXECUTE ON PROCEDURE ADD_EMP_PROJ TO PUBLIC WITH GRANT OPTION', 5766 'GRANT EXECUTE ON PROCEDURE SUB_TOT_BUDGET TO PUBLIC WITH GRANT OPTION', 5767 'GRANT EXECUTE ON PROCEDURE DELETE_EMPLOYEE TO PUBLIC WITH GRANT OPTION', 5768 'GRANT EXECUTE ON PROCEDURE DEPT_BUDGET TO PUBLIC WITH GRANT OPTION', 5769 'GRANT EXECUTE ON PROCEDURE ORG_CHART TO PUBLIC WITH GRANT OPTION', 5770 'GRANT EXECUTE ON PROCEDURE MAIL_LABEL TO PUBLIC WITH GRANT OPTION', 5771 'GRANT EXECUTE ON PROCEDURE SHIP_ORDER TO PUBLIC WITH GRANT OPTION', 5772 'GRANT EXECUTE ON PROCEDURE SHOW_LANGS TO PUBLIC WITH GRANT OPTION', 5773 'GRANT EXECUTE ON PROCEDURE ALL_LANGS TO PUBLIC WITH GRANT OPTION']) 5774 script = s.get_metadata_ddl([sm.SCRIPT_COMMENTS]) 5775 self.assertListEqual(script, ["COMMENT ON CHARACTER SET NONE IS 'Comment on NONE character set'"]) 5776 script = s.get_metadata_ddl([sm.SCRIPT_SHADOWS]) 5777 self.assertListEqual(script, []) 5778 script = s.get_metadata_ddl([sm.SCRIPT_INDEX_DEACTIVATIONS]) 5779 if self.version == FB30: 5780 self.assertListEqual(script, ['ALTER INDEX MINSALX INACTIVE', 5781 'ALTER INDEX MAXSALX INACTIVE', 5782 'ALTER INDEX BUDGETX INACTIVE', 5783 'ALTER INDEX NAMEX INACTIVE', 5784 'ALTER INDEX PRODTYPEX INACTIVE', 5785 'ALTER INDEX UPDATERX INACTIVE', 5786 'ALTER INDEX CHANGEX INACTIVE', 5787 'ALTER INDEX CUSTNAMEX INACTIVE', 5788 'ALTER INDEX CUSTREGION INACTIVE', 5789 'ALTER INDEX NEEDX INACTIVE', 5790 'ALTER INDEX SALESTATX INACTIVE', 5791 'ALTER INDEX QTYX INACTIVE']) 5792 else: 5793 self.assertListEqual(script, ['ALTER INDEX NEEDX INACTIVE', 5794 'ALTER INDEX SALESTATX INACTIVE', 5795 'ALTER INDEX QTYX INACTIVE', 5796 'ALTER INDEX UPDATERX INACTIVE', 5797 'ALTER INDEX CHANGEX INACTIVE', 5798 'ALTER INDEX PRODTYPEX INACTIVE', 5799 'ALTER INDEX CUSTNAMEX INACTIVE', 5800 'ALTER INDEX CUSTREGION INACTIVE', 5801 'ALTER INDEX NAMEX INACTIVE', 5802 'ALTER INDEX BUDGETX INACTIVE', 5803 'ALTER INDEX MINSALX INACTIVE', 5804 'ALTER INDEX MAXSALX INACTIVE']) 5805 script = s.get_metadata_ddl([sm.SCRIPT_INDEX_ACTIVATIONS]) 5806 if self.version == FB30: 5807 self.assertListEqual(script, ['ALTER INDEX MINSALX ACTIVE', 5808 'ALTER INDEX MAXSALX ACTIVE', 5809 'ALTER INDEX BUDGETX ACTIVE', 5810 'ALTER INDEX NAMEX ACTIVE', 5811 'ALTER INDEX PRODTYPEX ACTIVE', 5812 'ALTER INDEX UPDATERX ACTIVE', 5813 'ALTER INDEX CHANGEX ACTIVE', 5814 'ALTER INDEX CUSTNAMEX ACTIVE', 5815 'ALTER INDEX CUSTREGION ACTIVE', 5816 'ALTER INDEX NEEDX ACTIVE', 5817 'ALTER INDEX SALESTATX ACTIVE', 5818 'ALTER INDEX QTYX ACTIVE']) 5819 else: 5820 self.assertListEqual(script, ['ALTER INDEX NEEDX ACTIVE', 5821 'ALTER INDEX SALESTATX ACTIVE', 5822 'ALTER INDEX QTYX ACTIVE', 5823 'ALTER INDEX UPDATERX ACTIVE', 5824 'ALTER INDEX CHANGEX ACTIVE', 5825 'ALTER INDEX PRODTYPEX ACTIVE', 5826 'ALTER INDEX CUSTNAMEX ACTIVE', 5827 'ALTER INDEX CUSTREGION ACTIVE', 5828 'ALTER INDEX NAMEX ACTIVE', 5829 'ALTER INDEX BUDGETX ACTIVE', 5830 'ALTER INDEX MINSALX ACTIVE', 5831 'ALTER INDEX MAXSALX ACTIVE']) 5832 script = s.get_metadata_ddl([sm.SCRIPT_SET_GENERATORS]) 5833 self.assertListEqual(script, ['ALTER SEQUENCE EMP_NO_GEN RESTART WITH 145', 5834 'ALTER SEQUENCE CUST_NO_GEN RESTART WITH 1015']) 5835 script = s.get_metadata_ddl([sm.SCRIPT_TRIGGER_DEACTIVATIONS]) 5836 if self.version == FB30: 5837 self.assertListEqual(script, ['ALTER TRIGGER SET_EMP_NO INACTIVE', 5838 'ALTER TRIGGER SAVE_SALARY_CHANGE INACTIVE', 5839 'ALTER TRIGGER SET_CUST_NO INACTIVE', 5840 'ALTER TRIGGER POST_NEW_ORDER INACTIVE', 5841 'ALTER TRIGGER TR_CONNECT INACTIVE', 5842 'ALTER TRIGGER TR_MULTI INACTIVE']) 5843 else: 5844 self.assertListEqual(script, ['ALTER TRIGGER SET_EMP_NO INACTIVE', 5845 'ALTER TRIGGER SAVE_SALARY_CHANGE INACTIVE', 5846 'ALTER TRIGGER SET_CUST_NO INACTIVE', 5847 'ALTER TRIGGER POST_NEW_ORDER INACTIVE', 5848 'ALTER TRIGGER TR_MULTI INACTIVE', 5849 'ALTER TRIGGER TR_CONNECT INACTIVE']) 5850 script = s.get_metadata_ddl([sm.SCRIPT_TRIGGER_ACTIVATIONS]) 5851 if self.version == FB30: 5852 self.assertListEqual(script, ['ALTER TRIGGER SET_EMP_NO ACTIVE', 5853 'ALTER TRIGGER SAVE_SALARY_CHANGE ACTIVE', 5854 'ALTER TRIGGER SET_CUST_NO ACTIVE', 5855 'ALTER TRIGGER POST_NEW_ORDER ACTIVE', 5856 'ALTER TRIGGER TR_CONNECT ACTIVE', 5857 'ALTER TRIGGER TR_MULTI ACTIVE']) 5858 else: 5859 self.assertListEqual(script, ['ALTER TRIGGER SET_EMP_NO ACTIVE', 5860 'ALTER TRIGGER SAVE_SALARY_CHANGE ACTIVE', 5861 'ALTER TRIGGER SET_CUST_NO ACTIVE', 5862 'ALTER TRIGGER POST_NEW_ORDER ACTIVE', 5863 'ALTER TRIGGER TR_MULTI ACTIVE', 5864 'ALTER TRIGGER TR_CONNECT ACTIVE']) 5865 5866class TestMonitor(FDBTestBase): 5867 def setUp(self): 5868 super(TestMonitor, self).setUp() 5869 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 5870 self.con = fdb.connect(host=FBTEST_HOST, database=self.dbfile, 5871 user=FBTEST_USER, password=FBTEST_PASSWORD) 5872 def tearDown(self): 5873 self.con.close() 5874 def testMonitorBindClose(self): 5875 if self.con.ods < fdb.ODS_FB_21: 5876 return 5877 s = fdb.monitor.Monitor() 5878 self.assertTrue(s.closed) 5879 s.bind(self.con) 5880 # properties 5881 self.assertEqual(s.db.name.upper(), self.dbfile.upper()) 5882 self.assertFalse(s.db.read_only) 5883 self.assertFalse(s.closed) 5884 # 5885 s.close() 5886 self.assertTrue(s.closed) 5887 s.bind(self.con) 5888 self.assertFalse(s.closed) 5889 # 5890 s.bind(self.con) 5891 self.assertFalse(s.closed) 5892 # 5893 del s 5894 def testMonitor(self): 5895 if self.con.ods < fdb.ODS_FB_21: 5896 return 5897 c = self.con.cursor() 5898 sql = "select RDB$SET_CONTEXT('USER_SESSION','TESTVAR','TEST_VALUE') from rdb$database" 5899 c.execute(sql) 5900 c.fetchone() 5901 m = self.con.monitor 5902 m.refresh() 5903 self.assertIsNotNone(m.db) 5904 self.assertIsInstance(m.db, fdb.monitor.DatabaseInfo) 5905 self.assertGreater(len(m.attachments), 0) 5906 self.assertIsInstance(m.attachments[0], fdb.monitor.AttachmentInfo) 5907 self.assertGreater(len(m.transactions), 0) 5908 self.assertIsInstance(m.transactions[0], fdb.monitor.TransactionInfo) 5909 self.assertGreater(len(m.statements), 0) 5910 self.assertIsInstance(m.statements[0], fdb.monitor.StatementInfo) 5911 self.assertEqual(len(m.callstack), 0) 5912 self.assertGreater(len(m.iostats), 0) 5913 self.assertIsInstance(m.iostats[0], fdb.monitor.IOStatsInfo) 5914 if self.con.ods == fdb.ODS_FB_21: 5915 self.assertEqual(len(m.variables), 0) 5916 elif self.con.ods >= fdb.ODS_FB_25: 5917 self.assertGreater(len(m.variables), 0) 5918 self.assertIsInstance(m.variables[0], fdb.monitor.ContextVariableInfo) 5919 # 5920 att_id = m._con.db_info(fdb.isc_info_attachment_id) 5921 self.assertEqual(m.get_attachment(att_id).id, att_id) 5922 tra_id = m._con.trans_info(fdb.isc_info_tra_id) 5923 self.assertEqual(m.get_transaction(tra_id).id, tra_id) 5924 stmt_id = None 5925 for stmt in m.statements: 5926 if stmt.sql_text == sql: 5927 stmt_id = stmt.id 5928 self.assertEqual(m.get_statement(stmt_id).id, stmt_id) 5929 # m.get_call() 5930 self.assertIsInstance(m.this_attachment, fdb.monitor.AttachmentInfo) 5931 self.assertEqual(m.this_attachment.id, 5932 self.con.db_info(fdb.isc_info_attachment_id)) 5933 self.assertFalse(m.closed) 5934 # 5935 with self.assertRaises(fdb.ProgrammingError) as cm: 5936 m.close() 5937 self.assertTupleEqual(cm.exception.args, 5938 ("Call to 'close' not allowed for embedded Monitor.",)) 5939 with self.assertRaises(fdb.ProgrammingError) as cm: 5940 m.bind(self.con) 5941 self.assertTupleEqual(cm.exception.args, 5942 ("Call to 'bind' not allowed for embedded Monitor.",)) 5943 def testDatabaseInfo(self): 5944 if self.con.ods < fdb.ODS_FB_21: 5945 return 5946 m = self.con.monitor 5947 m.refresh() 5948 self.assertEqual(m.db.name.upper(), self.dbfile.upper()) 5949 if self.con.ods < fdb.ODS_FB_30: 5950 self.assertEqual(m.db.page_size, 4096) 5951 else: 5952 self.assertEqual(m.db.page_size, 8192) 5953 if self.con.ods == fdb.ODS_FB_20: 5954 self.assertEqual(m.db.ods, 11.0) 5955 elif self.con.ods == fdb.ODS_FB_21: 5956 self.assertEqual(m.db.ods, 11.1) 5957 elif self.con.ods == fdb.ODS_FB_25: 5958 self.assertEqual(m.db.ods, 11.2) 5959 elif self.con.ods >= fdb.ODS_FB_30: 5960 self.assertEqual(m.db.ods, 12.0) 5961 self.assertIsInstance(m.db.oit, int) 5962 self.assertIsInstance(m.db.oat, int) 5963 self.assertIsInstance(m.db.ost, int) 5964 self.assertIsInstance(m.db.next_transaction, int) 5965 self.assertIsInstance(m.db.cache_size, int) 5966 self.assertEqual(m.db.sql_dialect, 3) 5967 self.assertEqual(m.db.shutdown_mode, fdb.monitor.SHUTDOWN_MODE_ONLINE) 5968 self.assertEqual(m.db.sweep_interval, 20000) 5969 self.assertFalse(m.db.read_only) 5970 self.assertTrue(m.db.forced_writes) 5971 self.assertTrue(m.db.reserve_space) 5972 self.assertIsInstance(m.db.created, datetime.datetime) 5973 self.assertIsInstance(m.db.pages, int) 5974 self.assertEqual(m.db.backup_state, fdb.monitor.BACKUP_STATE_NORMAL) 5975 if self.con.ods < fdb.ODS_FB_30: 5976 self.assertIsNone(m.db.crypt_page) 5977 self.assertIsNone(m.db.owner) 5978 self.assertIsNone(m.db.security_database) 5979 else: 5980 self.assertEqual(m.db.crypt_page, 0) 5981 self.assertEqual(m.db.owner, 'SYSDBA') 5982 self.assertEqual(m.db.security_database, 'Default') 5983 self.assertEqual(m.db.iostats.group, fdb.monitor.STAT_DATABASE) 5984 self.assertEqual(m.db.iostats.stat_id, m.db.stat_id) 5985 self.assertIsInstance(m.db.tablestats, dict) 5986 if self.con.ods < fdb.ODS_FB_30: 5987 self.assertEqual(len(m.db.tablestats), 0) 5988 else: 5989 self.assertGreater(len(m.db.tablestats), 0) 5990 def testAttachmentInfo(self): 5991 if self.con.ods < fdb.ODS_FB_21: 5992 return 5993 c = self.con.cursor() 5994 sql = "select RDB$SET_CONTEXT('USER_SESSION','TESTVAR','TEST_VALUE') from rdb$database" 5995 c.execute(sql) 5996 c.fetchone() 5997 m = self.con.monitor 5998 m.refresh() 5999 s = m.this_attachment 6000 # 6001 self.assertEqual(s.id, self.con.db_info(fdb.isc_info_attachment_id)) 6002 self.assertIsInstance(s.server_pid, int) 6003 self.assertIn(s.state, [fdb.monitor.STATE_ACTIVE, fdb.monitor.STATE_IDLE]) 6004 self.assertEqual(s.name.upper(), self.dbfile.upper()) 6005 self.assertEqual(s.user, 'SYSDBA') 6006 self.assertEqual(s.role, 'NONE') 6007 if not FBTEST_HOST and self.con.engine_version >= 3.0: 6008 self.assertIsNone(s.remote_protocol) 6009 self.assertIsNone(s.remote_address) 6010 self.assertIsNone(s.remote_pid) 6011 self.assertIsNone(s.remote_process) 6012 else: 6013 self.assertIn(s.remote_protocol, ['XNET', 'TCPv4', 'TCPv6']) 6014 self.assertIsInstance(s.remote_address, str) 6015 self.assertIsInstance(s.remote_pid, int) 6016 self.assertIsInstance(s.remote_process, str) 6017 self.assertIsInstance(s.character_set, sm.CharacterSet) 6018 self.assertIsInstance(s.timestamp, datetime.datetime) 6019 self.assertIsInstance(s.transactions, list) 6020 if self.con.ods < fdb.ODS_FB_30: 6021 self.assertIsNone(s.auth_method) 6022 self.assertIsNone(s.client_version) 6023 self.assertIsNone(s.remote_version) 6024 self.assertIsNone(s.remote_os_user) 6025 self.assertIsNone(s.remote_host) 6026 else: 6027 self.assertIn(s.auth_method, ['Srp', 'Win_Sspi', 'Legacy_Auth']) 6028 self.assertIsInstance(s.client_version, str) 6029 self.assertEqual(s.remote_version, 'P15') # Firebird 3.0.3, may fail with other versions 6030 self.assertIsInstance(s.remote_os_user, str) 6031 self.assertIsInstance(s.remote_host, str) 6032 for x in s.transactions: 6033 self.assertIsInstance(x, fdb.monitor.TransactionInfo) 6034 self.assertIsInstance(s.statements, list) 6035 for x in s.statements: 6036 self.assertIsInstance(x, fdb.monitor.StatementInfo) 6037 self.assertIsInstance(s.variables, list) 6038 if self.con.ods >= fdb.ODS_FB_25: 6039 self.assertGreater(len(s.variables), 0) 6040 else: 6041 self.assertEqual(len(s.variables), 0) 6042 for x in s.variables: 6043 self.assertIsInstance(x, fdb.monitor.ContextVariableInfo) 6044 self.assertEqual(s.iostats.group, fdb.monitor.STAT_ATTACHMENT) 6045 self.assertEqual(s.iostats.stat_id, s.stat_id) 6046 if self.con.ods < fdb.ODS_FB_30: 6047 self.assertEqual(len(m.db.tablestats), 0) 6048 else: 6049 self.assertGreater(len(m.db.tablestats), 0) 6050 # 6051 self.assertTrue(s.isactive()) 6052 self.assertFalse(s.isidle()) 6053 self.assertFalse(s.isinternal()) 6054 self.assertTrue(s.isgcallowed()) 6055 def testTransactionInfo(self): 6056 if self.con.ods < fdb.ODS_FB_21: 6057 return 6058 c = self.con.cursor() 6059 sql = "select RDB$SET_CONTEXT('USER_TRANSACTION','TESTVAR','TEST_VALUE') from rdb$database" 6060 c.execute(sql) 6061 c.fetchone() 6062 m = self.con.monitor 6063 m.refresh() 6064 s = m.this_attachment.transactions[0] 6065 # 6066 self.assertEqual(s.id, m._ic.transaction.trans_info(fdb.isc_info_tra_id)) 6067 self.assertIs(s.attachment, m.this_attachment) 6068 self.assertIn(s.state, [fdb.monitor.STATE_ACTIVE, fdb.monitor.STATE_IDLE]) 6069 self.assertIsInstance(s.timestamp, datetime.datetime) 6070 self.assertIsInstance(s.top, int) 6071 self.assertIsInstance(s.oldest, int) 6072 self.assertIsInstance(s.oldest_active, int) 6073 self.assertEqual(s.isolation_mode, fdb.monitor.ISOLATION_READ_COMMITTED_RV) 6074 self.assertEqual(s.lock_timeout, fdb.monitor.INFINITE_WAIT) 6075 self.assertIsInstance(s.statements, list) 6076 for x in s.statements: 6077 self.assertIsInstance(x, fdb.monitor.StatementInfo) 6078 self.assertIsInstance(s.variables, list) 6079 self.assertEqual(s.iostats.group, fdb.monitor.STAT_TRANSACTION) 6080 self.assertEqual(s.iostats.stat_id, s.stat_id) 6081 if self.con.ods < fdb.ODS_FB_30: 6082 self.assertEqual(len(m.db.tablestats), 0) 6083 else: 6084 self.assertGreater(len(m.db.tablestats), 0) 6085 # 6086 self.assertTrue(s.isactive()) 6087 self.assertFalse(s.isidle()) 6088 self.assertTrue(s.isreadonly()) 6089 self.assertFalse(s.isautocommit()) 6090 self.assertTrue(s.isautoundo()) 6091 # 6092 s = m.get_transaction(c.transaction.trans_info(fdb.isc_info_tra_id)) 6093 self.assertIsInstance(s.variables, list) 6094 if self.con.ods >= fdb.ODS_FB_25: 6095 self.assertGreater(len(s.variables), 0) 6096 else: 6097 self.assertEqual(len(s.variables), 0) 6098 for x in s.variables: 6099 self.assertIsInstance(x, fdb.monitor.ContextVariableInfo) 6100 def testStatementInfo(self): 6101 if self.con.ods < fdb.ODS_FB_21: 6102 return 6103 m = self.con.monitor 6104 m.refresh() 6105 s = m.this_attachment.statements[0] 6106 # 6107 self.assertIsInstance(s.id, int) 6108 self.assertIs(s.attachment, m.this_attachment) 6109 self.assertEqual(s.transaction.id, m.transactions[0].id) 6110 self.assertIn(s.state, [fdb.monitor.STATE_ACTIVE, fdb.monitor.STATE_IDLE]) 6111 self.assertIsInstance(s.timestamp, datetime.datetime) 6112 self.assertEqual(s.sql_text, "select * from mon$database") 6113 if self.con.ods < fdb.ODS_FB_30: 6114 self.assertIsNone(s.plan) 6115 else: 6116 self.assertEqual(s.plan, 'Select Expression\n -> Table "MON$DATABASE" Full Scan') 6117 # We have to use mocks for callstack 6118 stack = utils.ObjectList() 6119 stack.append(fdb.monitor.CallStackInfo(m, 6120 {'MON$CALL_ID':1, 'MON$STATEMENT_ID':s.id-1, 'MON$CALLER_ID':None, 6121 'MON$OBJECT_NAME':'TRIGGER_1', 'MON$OBJECT_TYPE':2, 'MON$TIMESTAMP':datetime.datetime.now(), 6122 'MON$SOURCE_LINE':1, 'MON$SOURCE_COLUMN':1, 'MON$STAT_ID':s.stat_id+100})) 6123 stack.append(fdb.monitor.CallStackInfo(m, 6124 {'MON$CALL_ID':2, 'MON$STATEMENT_ID':s.id, 'MON$CALLER_ID':None, 6125 'MON$OBJECT_NAME':'TRIGGER_2', 'MON$OBJECT_TYPE':2, 'MON$TIMESTAMP':datetime.datetime.now(), 6126 'MON$SOURCE_LINE':1, 'MON$SOURCE_COLUMN':1, 'MON$STAT_ID':s.stat_id+101})) 6127 stack.append(fdb.monitor.CallStackInfo(m, 6128 {'MON$CALL_ID':3, 'MON$STATEMENT_ID':s.id, 'MON$CALLER_ID':2, 6129 'MON$OBJECT_NAME':'PROC_1', 'MON$OBJECT_TYPE':5, 'MON$TIMESTAMP':datetime.datetime.now(), 6130 'MON$SOURCE_LINE':2, 'MON$SOURCE_COLUMN':2, 'MON$STAT_ID':s.stat_id+102})) 6131 stack.append(fdb.monitor.CallStackInfo(m, 6132 {'MON$CALL_ID':4, 'MON$STATEMENT_ID':s.id, 'MON$CALLER_ID':3, 6133 'MON$OBJECT_NAME':'PROC_2', 'MON$OBJECT_TYPE':5, 'MON$TIMESTAMP':datetime.datetime.now(), 6134 'MON$SOURCE_LINE':3, 'MON$SOURCE_COLUMN':3, 'MON$STAT_ID':s.stat_id+103})) 6135 stack.append(fdb.monitor.CallStackInfo(m, 6136 {'MON$CALL_ID':5, 'MON$STATEMENT_ID':s.id+1, 'MON$CALLER_ID':None, 6137 'MON$OBJECT_NAME':'PROC_3', 'MON$OBJECT_TYPE':5, 'MON$TIMESTAMP':datetime.datetime.now(), 6138 'MON$SOURCE_LINE':1, 'MON$SOURCE_COLUMN':1, 'MON$STAT_ID':s.stat_id+104})) 6139 m.__dict__['_Monitor__callstack'] = stack 6140 # 6141 self.assertListEqual(s.callstack, [stack[1], stack[2], stack[3]]) 6142 self.assertEqual(s.iostats.group, fdb.monitor.STAT_STATEMENT) 6143 self.assertEqual(s.iostats.stat_id, s.stat_id) 6144 if self.con.ods < fdb.ODS_FB_30: 6145 self.assertEqual(len(m.db.tablestats), 0) 6146 else: 6147 self.assertGreater(len(m.db.tablestats), 0) 6148 # 6149 self.assertTrue(s.isactive()) 6150 self.assertFalse(s.isidle()) 6151 def testCallStackInfo(self): 6152 if self.con.ods < fdb.ODS_FB_21: 6153 return 6154 m = self.con.monitor 6155 m.refresh() 6156 stmt = m.this_attachment.statements[0] 6157 # We have to use mocks for callstack 6158 stack = utils.ObjectList() 6159 stack.append(fdb.monitor.CallStackInfo(m, 6160 {'MON$CALL_ID':1, 'MON$STATEMENT_ID':stmt.id-1, 'MON$CALLER_ID':None, 6161 'MON$OBJECT_NAME':'POST_NEW_ORDER', 'MON$OBJECT_TYPE':2, 'MON$TIMESTAMP':datetime.datetime.now(), 6162 'MON$SOURCE_LINE':1, 'MON$SOURCE_COLUMN':1, 'MON$STAT_ID':stmt.stat_id+100})) 6163 stack.append(fdb.monitor.CallStackInfo(m, 6164 {'MON$CALL_ID':2, 'MON$STATEMENT_ID':stmt.id, 'MON$CALLER_ID':None, 6165 'MON$OBJECT_NAME':'POST_NEW_ORDER', 'MON$OBJECT_TYPE':2, 'MON$TIMESTAMP':datetime.datetime.now(), 6166 'MON$SOURCE_LINE':1, 'MON$SOURCE_COLUMN':1, 'MON$STAT_ID':stmt.stat_id+101})) 6167 stack.append(fdb.monitor.CallStackInfo(m, 6168 {'MON$CALL_ID':3, 'MON$STATEMENT_ID':stmt.id, 'MON$CALLER_ID':2, 6169 'MON$OBJECT_NAME':'SHIP_ORDER', 'MON$OBJECT_TYPE':5, 'MON$TIMESTAMP':datetime.datetime.now(), 6170 'MON$SOURCE_LINE':2, 'MON$SOURCE_COLUMN':2, 'MON$STAT_ID':stmt.stat_id+102})) 6171 stack.append(fdb.monitor.CallStackInfo(m, 6172 {'MON$CALL_ID':4, 'MON$STATEMENT_ID':stmt.id, 'MON$CALLER_ID':3, 6173 'MON$OBJECT_NAME':'SUB_TOT_BUDGET', 'MON$OBJECT_TYPE':5, 'MON$TIMESTAMP':datetime.datetime.now(), 6174 'MON$SOURCE_LINE':3, 'MON$SOURCE_COLUMN':3, 'MON$STAT_ID':stmt.stat_id+103})) 6175 stack.append(fdb.monitor.CallStackInfo(m, 6176 {'MON$CALL_ID':5, 'MON$STATEMENT_ID':stmt.id+1, 'MON$CALLER_ID':None, 6177 'MON$OBJECT_NAME':'SUB_TOT_BUDGET', 'MON$OBJECT_TYPE':5, 'MON$TIMESTAMP':datetime.datetime.now(), 6178 'MON$SOURCE_LINE':1, 'MON$SOURCE_COLUMN':1, 'MON$STAT_ID':stmt.stat_id+104})) 6179 m.__dict__['_Monitor__callstack'] = stack 6180 data = m.iostats[0]._attributes 6181 data['MON$STAT_ID'] = stmt.stat_id+101 6182 data['MON$STAT_GROUP'] = fdb.monitor.STAT_CALL 6183 m.__dict__['_Monitor__iostats'] = utils.ObjectList(m.iostats) 6184 m.__dict__['_Monitor__iostats'].append(fdb.monitor.IOStatsInfo(m, data)) 6185 # 6186 s = m.get_call(2) 6187 # 6188 self.assertEqual(s.id, 2) 6189 self.assertIs(s.statement, m.get_statement(stmt.id)) 6190 self.assertIsNone(s.caller) 6191 self.assertIsInstance(s.dbobject, sm.Trigger) 6192 self.assertEqual(s.dbobject.name, 'POST_NEW_ORDER') 6193 self.assertIsInstance(s.timestamp, datetime.datetime) 6194 self.assertEqual(s.line, 1) 6195 self.assertEqual(s.column, 1) 6196 self.assertEqual(s.iostats.group, fdb.monitor.STAT_CALL) 6197 self.assertEqual(s.iostats.stat_id, s.stat_id) 6198 # 6199 x = m.get_call(3) 6200 self.assertIs(x.caller, s) 6201 self.assertIsInstance(x.dbobject, sm.Procedure) 6202 self.assertEqual(x.dbobject.name, 'SHIP_ORDER') 6203 def testIOStatsInfo(self): 6204 if self.con.ods < fdb.ODS_FB_21: 6205 return 6206 m = self.con.monitor 6207 m.refresh() 6208 # 6209 for io in m.iostats: 6210 self.assertIs(io, io.owner.iostats) 6211 # 6212 s = m.iostats[0] 6213 self.assertIsInstance(s.owner, fdb.monitor.DatabaseInfo) 6214 self.assertEqual(s.group, fdb.monitor.STAT_DATABASE) 6215 self.assertIsInstance(s.reads, int) 6216 self.assertIsInstance(s.writes, int) 6217 self.assertIsInstance(s.fetches, int) 6218 self.assertIsInstance(s.marks, int) 6219 self.assertIsInstance(s.seq_reads, int) 6220 self.assertIsInstance(s.idx_reads, int) 6221 self.assertIsInstance(s.inserts, int) 6222 self.assertIsInstance(s.updates, int) 6223 self.assertIsInstance(s.deletes, int) 6224 self.assertIsInstance(s.backouts, int) 6225 self.assertIsInstance(s.purges, int) 6226 self.assertIsInstance(s.expunges, int) 6227 if self.con.ods >= fdb.ODS_FB_30: 6228 self.assertIsInstance(s.locks, int) 6229 self.assertIsInstance(s.waits, int) 6230 self.assertIsInstance(s.conflits, int) 6231 self.assertIsInstance(s.backversion_reads, int) 6232 self.assertIsInstance(s.fragment_reads, int) 6233 self.assertIsInstance(s.repeated_reads, int) 6234 else: 6235 self.assertIsNone(s.locks) 6236 self.assertIsNone(s.waits) 6237 self.assertIsNone(s.conflits) 6238 self.assertIsNone(s.backversion_reads) 6239 self.assertIsNone(s.fragment_reads) 6240 self.assertIsNone(s.repeated_reads) 6241 if self.con.ods >= fdb.ODS_FB_25: 6242 self.assertIsInstance(s.memory_used, int) 6243 self.assertIsInstance(s.memory_allocated, int) 6244 self.assertIsInstance(s.max_memory_used, int) 6245 self.assertIsInstance(s.max_memory_allocated, int) 6246 else: 6247 self.assertIsNone(s.memory_used) 6248 self.assertIsNone(s.memory_allocated) 6249 self.assertIsNone(s.max_memory_used) 6250 self.assertIsNone(s.max_memory_allocated) 6251 def testContextVariableInfo(self): 6252 if self.con.ods <= fdb.ODS_FB_21: 6253 return 6254 c = self.con.cursor() 6255 sql = "select RDB$SET_CONTEXT('USER_SESSION','SVAR','TEST_VALUE') from rdb$database" 6256 c.execute(sql) 6257 c.fetchone() 6258 c = self.con.cursor() 6259 sql = "select RDB$SET_CONTEXT('USER_TRANSACTION','TVAR','TEST_VALUE') from rdb$database" 6260 c.execute(sql) 6261 c.fetchone() 6262 m = self.con.monitor 6263 m.refresh() 6264 # 6265 self.assertEqual(len(m.variables), 2) 6266 # 6267 s = m.variables[0] 6268 self.assertIs(s.attachment, m.this_attachment) 6269 self.assertIsNone(s.transaction) 6270 self.assertEqual(s.name, 'SVAR') 6271 self.assertEqual(s.value, 'TEST_VALUE') 6272 self.assertTrue(s.isattachmentvar()) 6273 self.assertFalse(s.istransactionvar()) 6274 # 6275 s = m.variables[1] 6276 self.assertIsNone(s.attachment) 6277 self.assertIs(s.transaction, 6278 m.get_transaction(c.transaction.trans_info(fdb.isc_info_tra_id))) 6279 self.assertEqual(s.name, 'TVAR') 6280 self.assertEqual(s.value, 'TEST_VALUE') 6281 self.assertFalse(s.isattachmentvar()) 6282 self.assertTrue(s.istransactionvar()) 6283 6284 6285class TestConnectionWithSchema(FDBTestBase): 6286 def setUp(self): 6287 super(TestConnectionWithSchema, self).setUp() 6288 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 6289 #self.con = fdb.connect(dsn=self.dbfile,user=FBTEST_USER,password=FBTEST_PASSWORD) 6290 def tearDown(self): 6291 #self.con.close() 6292 pass 6293 def testConnectSchema(self): 6294 s = fdb.connect(host=FBTEST_HOST, database=self.dbfile, user=FBTEST_USER, 6295 password=FBTEST_PASSWORD, 6296 connection_class=fdb.ConnectionWithSchema) 6297 if s.ods < fdb.ODS_FB_30: 6298 self.assertEqual(len(s.tables), 15) 6299 else: 6300 self.assertEqual(len(s.tables), 16) 6301 self.assertEqual(s.get_table('JOB').name, 'JOB') 6302 6303 6304class TestHooks(FDBTestBase): 6305 def setUp(self): 6306 super(TestHooks, self).setUp() 6307 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 6308 def __hook_service_attached(self, con): 6309 self._svc = con 6310 return con 6311 def __hook_db_attached(self, con): 6312 self._db = con 6313 return con 6314 def __hook_db_attach_request_a(self, dsn, dpb): 6315 return None 6316 def __hook_db_attach_request_b(self, dsn, dpb): 6317 return self._hook_con 6318 def test_hook_db_attached(self): 6319 fdb.add_hook(fdb.HOOK_DATABASE_ATTACHED, 6320 self.__hook_db_attached) 6321 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) as con: 6322 self.assertEqual(con, self._db) 6323 fdb.remove_hook(fdb.HOOK_DATABASE_ATTACHED, 6324 self.__hook_db_attached) 6325 def test_hook_db_attach_request(self): 6326 self._hook_con = fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) 6327 fdb.add_hook(fdb.HOOK_DATABASE_ATTACH_REQUEST, 6328 self.__hook_db_attach_request_a) 6329 fdb.add_hook(fdb.HOOK_DATABASE_ATTACH_REQUEST, 6330 self.__hook_db_attach_request_b) 6331 self.assertListEqual([self.__hook_db_attach_request_a, 6332 self.__hook_db_attach_request_b], 6333 fdb.get_hooks(fdb.HOOK_DATABASE_ATTACH_REQUEST)) 6334 with fdb.connect(dsn=self.dbfile, user=FBTEST_USER, password=FBTEST_PASSWORD) as con: 6335 self.assertEqual(con, self._hook_con) 6336 self._hook_con.close() 6337 fdb.remove_hook(fdb.HOOK_DATABASE_ATTACH_REQUEST, 6338 self.__hook_db_attach_request_a) 6339 fdb.remove_hook(fdb.HOOK_DATABASE_ATTACH_REQUEST, 6340 self.__hook_db_attach_request_b) 6341 def test_hook_service_attached(self): 6342 fdb.add_hook(fdb.HOOK_SERVICE_ATTACHED, 6343 self.__hook_service_attached) 6344 svc = fdb.services.connect(host=FBTEST_HOST, password=FBTEST_PASSWORD) 6345 self.assertEqual(svc, self._svc) 6346 svc.close() 6347 fdb.remove_hook(fdb.HOOK_SERVICE_ATTACHED, 6348 self.__hook_service_attached) 6349 6350 6351class TestBugs(FDBTestBase): 6352 "Tests for bugs logged in tracker, URL pattern: http://tracker.firebirdsql.org/browse/PYFB-<number>" 6353 def setUp(self): 6354 super(TestBugs, self).setUp() 6355 self.dbfile = os.path.join(self.dbpath, 'fbbugs.fdb') 6356 if os.path.exists(self.dbfile): 6357 os.remove(self.dbfile) 6358 self.con = fdb.create_database(host=FBTEST_HOST, database=self.dbfile, 6359 user=FBTEST_USER, password=FBTEST_PASSWORD) 6360 def tearDown(self): 6361 self.con.drop_database() 6362 self.con.close() 6363 def test_pyfb_17(self): 6364 "(PYFB-17) NOT NULL constraint + Insert Trigger" 6365 create_table = """ 6366 Create Table table1 ( 6367 ID Integer, 6368 C1 Integer NOT Null 6369 ); 6370 """ 6371 6372 create_trigger = """CREATE TRIGGER BIU_Trigger FOR table1 6373 ACTIVE BEFORE INSERT OR UPDATE POSITION 0 6374 as 6375 begin 6376 if (new.C1 IS NULL) then 6377 begin 6378 new.C1 = 1; 6379 end 6380 end 6381 """ 6382 6383 cur = self.con.cursor() 6384 cur.execute(create_table) 6385 cur.execute(create_trigger) 6386 self.con.commit() 6387 # PYFB-17: fails with fdb, passes with kinterbasdb 6388 cur.execute('insert into table1 (ID, C1) values(1, ?)', (None, )) 6389 def test_pyfb_22(self): 6390 "(PYFB-22) SELECT FROM VARCHAR COLUMN WITH TEXT LONGER THAN 128 CHARS RETURN EMPTY STRING" 6391 create_table = """ 6392 CREATE TABLE FDBTEST ( 6393 ID INTEGER, 6394 TEST80 VARCHAR(80), 6395 TEST128 VARCHAR(128), 6396 TEST255 VARCHAR(255), 6397 TEST1024 VARCHAR(1024), 6398 TESTCLOB BLOB SUB_TYPE 1 SEGMENT SIZE 255 6399 ); 6400 """ 6401 cur = self.con.cursor() 6402 cur.execute(create_table) 6403 self.con.commit() 6404 # test data 6405 data = ("1234567890" * 25) + "12345" 6406 for i in ibase.xrange(255): 6407 cur.execute("insert into fdbtest (id, test255) values (?, ?)", 6408 (i, data[:i])) 6409 self.con.commit() 6410 # PYFB-22: fails with fdb, passes with kinterbasdb 6411 cur.execute("select test255 from fdbtest order by id") 6412 i = 0 6413 for row in cur: 6414 value = row[0] 6415 self.assertEqual(len(value), i) 6416 self.assertEqual(value, data[:i]) 6417 i += 1 6418 def test_pyfb_25(self): 6419 "(PYFB-25) Trancate long text from VARCHAR(5000)" 6420 create_table = """ 6421 CREATE TABLE FDBTEST2 ( 6422 ID INTEGER, 6423 TEST5000 VARCHAR(5000) 6424 ); 6425 """ 6426 cur = self.con.cursor() 6427 cur.execute(create_table) 6428 self.con.commit() 6429 # test data 6430 data = "1234567890" * 500 6431 cur.execute("insert into fdbtest2 (id, test5000) values (?, ?)", 6432 (1, data)) 6433 self.con.commit() 6434 # PYFB-25: fails with fdb, passes with kinterbasdb 6435 cur.execute("select test5000 from fdbtest2") 6436 row = cur.fetchone() 6437 self.assertEqual(row[0], data) 6438 def test_pyfb_30(self): 6439 "(PYFB-30) BLOBs are truncated at first zero byte" 6440 create_table = """ 6441 CREATE TABLE FDBTEST3 ( 6442 ID INTEGER, 6443 T_BLOB BLOB sub_type BINARY 6444 ); 6445 """ 6446 cur = self.con.cursor() 6447 cur.execute(create_table) 6448 self.con.commit() 6449 # test data 6450 data_bytes = (1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) 6451 blob_data = fdb.bs(data_bytes) 6452 cur.execute("insert into fdbtest3 (id, t_blob) values (?, ?)", 6453 (1, blob_data)) 6454 cur.execute("insert into fdbtest3 (id, t_blob) values (?, ?)", 6455 (2, BytesIO(blob_data))) 6456 self.con.commit() 6457 # PYFB-XX: binary blob trucated at zero-byte 6458 cur.execute("select t_blob from fdbtest3 where id = 1") 6459 row = cur.fetchone() 6460 self.assertEqual(row[0], blob_data) 6461 cur.execute("select t_blob from fdbtest3 where id = 2") 6462 row = cur.fetchone() 6463 self.assertEqual(row[0], blob_data) 6464 p = cur.prep("select t_blob from fdbtest3 where id = 2") 6465 p.set_stream_blob('T_BLOB') 6466 cur.execute(p) 6467 blob_reader = cur.fetchone()[0] 6468 value = blob_reader.read() 6469 self.assertEqual(value, blob_data) 6470 def test_pyfb_34(self): 6471 "(PYFB-34) Server resources not released on PreparedStatement destruction" 6472 cur = self.con.cursor() 6473 cur.execute("select * from RDB$Relations") 6474 cur.fetchall() 6475 del cur 6476 def test_pyfb_35(self): 6477 "(PYFB-35) Call to fetch after a sql statement without a result should raise exception" 6478 create_table = """ 6479 Create Table table1 ( 6480 ID Integer, 6481 C1 Integer NOT Null 6482 ); 6483 """ 6484 6485 c = self.con.cursor() 6486 c.execute(create_table) 6487 self.con.commit() 6488 del c 6489 6490 cur = self.con.cursor() 6491 with self.assertRaises(fdb.DatabaseError) as cm: 6492 cur.fetchall() 6493 self.assertTupleEqual(cm.exception.args, 6494 ("Cannot fetch from this cursor because it has not executed a statement.",)) 6495 6496 cur.execute("select * from RDB$DATABASE") 6497 cur.fetchall() 6498 cur.execute("CREATE SEQUENCE TEST_SEQ_1") 6499 with self.assertRaises(fdb.DatabaseError) as cm: 6500 cur.fetchall() 6501 self.assertTupleEqual(cm.exception.args, 6502 ("Attempt to fetch row of results after statement that does not produce result set.",)) 6503 6504 cur.execute("insert into table1 (ID,C1) values (1,1) returning ID") 6505 row = cur.fetchall() 6506 self.assertListEqual(row, [(1,)]) 6507 6508 def test_pyfb_44(self): 6509 "(PYFB-44) Inserting a datetime.date into a TIMESTAMP column does not work" 6510 self.con2 = fdb.connect(host=FBTEST_HOST, database=os.path.join(self.dbpath, self.FBTEST_DB), 6511 user=FBTEST_USER, password=FBTEST_PASSWORD) 6512 try: 6513 cur = self.con2.cursor() 6514 now = datetime.datetime(2011, 11, 13, 15, 00, 1, 200) 6515 cur.execute('insert into T2 (C1,C8) values (?,?)', [3, now.date()]) 6516 self.con2.commit() 6517 cur.execute('select C1,C8 from T2 where C1 = 3') 6518 rows = cur.fetchall() 6519 self.assertListEqual(rows, 6520 [(3, datetime.datetime(2011, 11, 13, 0, 0, 0, 0))]) 6521 finally: 6522 self.con2.execute_immediate("delete from t2") 6523 self.con2.commit() 6524 self.con2.close() 6525 6526 6527 6528class TestTraceParse(FDBTestBase): 6529 def setUp(self): 6530 super(TestTraceParse, self).setUp() 6531 self.dbfile = os.path.join(self.dbpath, self.FBTEST_DB) 6532 def test_linesplit_iter(self): 6533 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6534 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6535 /opt/firebird/bin/isql:8723 6536 6537""" 6538 for line in linesplit_iter(trace_lines): 6539 self.output.write(line + '\n') 6540 self.assertEqual(self.output.getvalue(), trace_lines) 6541 def _check_events(self, trace_lines, output): 6542 parser = fdb.trace.TraceParser() 6543 for obj in parser.parse(linesplit_iter(trace_lines)): 6544 self.printout(str(obj)) 6545 #print(self.output.getvalue()) 6546 self.assertEqual(self.output.getvalue(), output, "Parsed events do not match expected ones") 6547 def test_trace_init(self): 6548 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) TRACE_INIT 6549 SESSION_1 6550 6551""" 6552 output = "EventTraceInit(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), session_name='SESSION_1')\n" 6553 self._check_events(trace_lines, output) 6554 def test_trace_suspend(self): 6555 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) TRACE_INIT 6556 SESSION_1 6557 6558--- Session 1 is suspended as its log is full --- 65592014-05-23T12:01:01.1420 (3720:0000000000EFD9E8) TRACE_INIT 6560 SESSION_1 6561 6562""" 6563 output = """EventTraceInit(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), session_name='SESSION_1') 6564EventTraceSuspend(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), session_name='SESSION_1') 6565EventTraceInit(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 12, 1, 1, 142000), session_name='SESSION_1') 6566""" 6567 self._check_events(trace_lines, output) 6568 def test_trace_finish(self): 6569 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) TRACE_INIT 6570 SESSION_1 6571 65722014-05-23T11:01:24.8080 (3720:0000000000EFD9E8) TRACE_FINI 6573 SESSION_1 6574 6575""" 6576 output = """EventTraceInit(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), session_name='SESSION_1') 6577EventTraceFinish(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 1, 24, 808000), session_name='SESSION_1') 6578""" 6579 self._check_events(trace_lines, output) 6580 def test_create_database(self): 6581 trace_lines = """2018-03-29T14:20:55.1180 (6290:0x7f9bb00bb978) CREATE_DATABASE 6582 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6583 /opt/firebird/bin/isql:8723 6584 6585""" 6586 output = """EventCreate(event_id=1, timestamp=datetime.datetime(2018, 3, 29, 14, 20, 55, 118000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6587""" 6588 self._check_events(trace_lines, output) 6589 def test_drop_database(self): 6590 trace_lines = """2018-03-29T14:20:55.1180 (6290:0x7f9bb00bb978) DROP_DATABASE 6591 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6592 /opt/firebird/bin/isql:8723 6593 6594""" 6595 output = """EventDrop(event_id=1, timestamp=datetime.datetime(2018, 3, 29, 14, 20, 55, 118000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6596""" 6597 self._check_events(trace_lines, output) 6598 def test_attach(self): 6599 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6600 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6601 /opt/firebird/bin/isql:8723 6602""" 6603 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6604""" 6605 self._check_events(trace_lines, output) 6606 def test_attach_failed(self): 6607 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) FAILED ATTACH_DATABASE 6608 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6609 /opt/firebird/bin/isql:8723 6610 6611""" 6612 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status='F', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6613""" 6614 self._check_events(trace_lines, output) 6615 def test_unauthorized_attach(self): 6616 trace_lines = """2014-09-24T14:46:15.0350 (2453:0x7fed02a04910) UNAUTHORIZED ATTACH_DATABASE 6617 /home/employee.fdb (ATT_0, sysdba, NONE, TCPv4:127.0.0.1) 6618 /opt/firebird/bin/isql:8723 6619 6620""" 6621 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 9, 24, 14, 46, 15, 35000), status='U', attachment_id=0, database='/home/employee.fdb', charset='NONE', protocol='TCPv4', address='127.0.0.1', user='sysdba', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6622""" 6623 self._check_events(trace_lines, output) 6624 def test_detach(self): 6625 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6626 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6627 /opt/firebird/bin/isql:8723 6628 66292014-05-23T11:01:24.8080 (3720:0000000000EFD9E8) DETACH_DATABASE 6630 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6631 /opt/firebird/bin/isql:8723 6632 6633""" 6634 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6635EventDetach(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 1, 24, 808000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6636""" 6637 self._check_events(trace_lines, output) 6638 def test_detach_without_attach(self): 6639 trace_lines = """2014-05-23T11:01:24.8080 (3720:0000000000EFD9E8) DETACH_DATABASE 6640 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6641 /opt/firebird/bin/isql:8723 6642 6643""" 6644 output = """EventDetach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 1, 24, 808000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6645""" 6646 self._check_events(trace_lines, output) 6647 def test_start_transaction(self): 6648 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6649 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6650 /opt/firebird/bin/isql:8723 6651 66522014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6653 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6654 /opt/firebird/bin/isql:8723 6655 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6656 6657""" 6658 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6659EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6660""" 6661 self._check_events(trace_lines, output) 6662 def test_start_transaction_without_attachment(self): 6663 trace_lines = """2014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6664 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6665 /opt/firebird/bin/isql:8723 6666 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6667 6668""" 6669 output = """AttachmentInfo(attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6670EventTransactionStart(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6671""" 6672 self._check_events(trace_lines, output) 6673 def test_commit(self): 6674 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6675 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6676 /opt/firebird/bin/isql:8723 6677 66782014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6679 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6680 /opt/firebird/bin/isql:8723 6681 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6682 66832014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) COMMIT_TRANSACTION 6684 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6685 /opt/firebird/bin/isql:8723 6686 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6687 0 ms, 1 read(s), 1 write(s), 1 fetch(es), 1 mark(s) 6688 6689""" 6690 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6691EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6692EventCommit(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=0, reads=1, writes=1, fetches=1, marks=1) 6693""" 6694 self._check_events(trace_lines, output) 6695 def test_commit_no_performance(self): 6696 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6697 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6698 /opt/firebird/bin/isql:8723 6699 67002014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6701 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6702 /opt/firebird/bin/isql:8723 6703 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6704 67052014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) COMMIT_TRANSACTION 6706 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6707 /opt/firebird/bin/isql:8723 6708 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6709 6710""" 6711 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6712EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6713EventCommit(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=None, reads=None, writes=None, fetches=None, marks=None) 6714""" 6715 self._check_events(trace_lines, output) 6716 def test_commit_without_attachment_and_start(self): 6717 trace_lines = """2014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) COMMIT_TRANSACTION 6718 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6719 /opt/firebird/bin/isql:8723 6720 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6721 0 ms, 1 read(s), 1 write(s), 1 fetch(es), 1 mark(s) 6722 6723""" 6724 output = """AttachmentInfo(attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6725EventCommit(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=0, reads=1, writes=1, fetches=1, marks=1) 6726""" 6727 self._check_events(trace_lines, output) 6728 def test_rollback(self): 6729 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6730 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6731 /opt/firebird/bin/isql:8723 6732 67332014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6734 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6735 /opt/firebird/bin/isql:8723 6736 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6737 67382014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) ROLLBACK_TRANSACTION 6739 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6740 /opt/firebird/bin/isql:8723 6741 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 67420 ms 6743 6744""" 6745 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6746EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6747EventRollback(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=0, reads=None, writes=None, fetches=None, marks=None) 6748""" 6749 self._check_events(trace_lines, output) 6750 def test_rollback_no_performance(self): 6751 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6752 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6753 /opt/firebird/bin/isql:8723 6754 67552014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6756 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6757 /opt/firebird/bin/isql:8723 6758 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6759 67602014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) ROLLBACK_TRANSACTION 6761 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6762 /opt/firebird/bin/isql:8723 6763 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6764 6765""" 6766 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6767EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6768EventRollback(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=None, reads=None, writes=None, fetches=None, marks=None) 6769""" 6770 self._check_events(trace_lines, output) 6771 def test_rollback_attachment_and_start(self): 6772 trace_lines = """2014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) ROLLBACK_TRANSACTION 6773 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6774 /opt/firebird/bin/isql:8723 6775 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 67760 ms 6777 6778""" 6779 output = """AttachmentInfo(attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6780EventRollback(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=0, reads=None, writes=None, fetches=None, marks=None) 6781""" 6782 self._check_events(trace_lines, output) 6783 def test_commit_retaining(self): 6784 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6785 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6786 /opt/firebird/bin/isql:8723 6787 67882014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6789 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6790 /opt/firebird/bin/isql:8723 6791 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6792 67932014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) COMMIT_RETAINING 6794 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6795 /opt/firebird/bin/isql:8723 6796 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6797 0 ms, 1 read(s), 1 write(s), 1 fetch(es), 1 mark(s) 6798 6799""" 6800 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6801EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6802EventCommitRetaining(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=0, reads=1, writes=1, fetches=1, marks=1) 6803""" 6804 self._check_events(trace_lines, output) 6805 def test_commit_retaining_no_performance(self): 6806 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6807 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6808 /opt/firebird/bin/isql:8723 6809 68102014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6811 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6812 /opt/firebird/bin/isql:8723 6813 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6814 68152014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) COMMIT_RETAINING 6816 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6817 /opt/firebird/bin/isql:8723 6818 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6819 6820""" 6821 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6822EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6823EventCommitRetaining(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=None, reads=None, writes=None, fetches=None, marks=None) 6824""" 6825 self._check_events(trace_lines, output) 6826 def test_commit_retaining_without_attachment_and_start(self): 6827 trace_lines = """2014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) COMMIT_RETAINING 6828 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6829 /opt/firebird/bin/isql:8723 6830 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6831 0 ms, 1 read(s), 1 write(s), 1 fetch(es), 1 mark(s) 6832 6833""" 6834 output = """AttachmentInfo(attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6835EventCommitRetaining(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=0, reads=1, writes=1, fetches=1, marks=1) 6836""" 6837 self._check_events(trace_lines, output) 6838 def test_rollback_retaining(self): 6839 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6840 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6841 /opt/firebird/bin/isql:8723 6842 68432014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6844 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6845 /opt/firebird/bin/isql:8723 6846 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6847 68482014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) ROLLBACK_RETAINING 6849 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6850 /opt/firebird/bin/isql:8723 6851 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 68520 ms 6853 6854""" 6855 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6856EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6857EventRollbackRetaining(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=0, reads=None, writes=None, fetches=None, marks=None) 6858""" 6859 self._check_events(trace_lines, output) 6860 def test_rollback_retaining_no_performance(self): 6861 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6862 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6863 /opt/firebird/bin/isql:8723 6864 68652014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6866 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6867 /opt/firebird/bin/isql:8723 6868 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6869 68702014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) ROLLBACK_RETAINING 6871 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6872 /opt/firebird/bin/isql:8723 6873 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6874 6875""" 6876 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6877EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6878EventRollbackRetaining(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=None, reads=None, writes=None, fetches=None, marks=None) 6879""" 6880 self._check_events(trace_lines, output) 6881 def test_rollback_retaining_without_attachment_and_start(self): 6882 trace_lines = """2014-05-23T11:00:29.9570 (3720:0000000000EFD9E8) ROLLBACK_RETAINING 6883 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6884 /opt/firebird/bin/isql:8723 6885 (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 68860 ms 6887 6888""" 6889 output = """AttachmentInfo(attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6890EventRollbackRetaining(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 29, 957000), status=' ', attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=0, reads=None, writes=None, fetches=None, marks=None) 6891""" 6892 self._check_events(trace_lines, output) 6893 def test_prepare_statement(self): 6894 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6895 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6896 /opt/firebird/bin/isql:8723 6897 68982014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6899 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6900 /opt/firebird/bin/isql:8723 6901 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6902 69032014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) PREPARE_STATEMENT 6904 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6905 /opt/firebird/bin/isql:8723 6906 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6907 6908Statement 181: 6909------------------------------------------------------------------------------- 6910SELECT GEN_ID(GEN_NUM, 1) FROM RDB$DATABASE 6911^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6912PLAN (RDB$DATABASE NATURAL) 6913 13 ms 6914 6915""" 6916 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6917EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6918SQLInfo(sql_id=1, sql='SELECT GEN_ID(GEN_NUM, 1) FROM RDB$DATABASE', plan='PLAN (RDB$DATABASE NATURAL)') 6919EventPrepareStatement(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, statement_id=181, sql_id=1, prepare_time=13) 6920""" 6921 self._check_events(trace_lines, output) 6922 def test_prepare_statement_no_plan(self): 6923 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6924 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6925 /opt/firebird/bin/isql:8723 6926 69272014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6928 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6929 /opt/firebird/bin/isql:8723 6930 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6931 69322014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) PREPARE_STATEMENT 6933 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6934 /opt/firebird/bin/isql:8723 6935 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6936 6937Statement 181: 6938------------------------------------------------------------------------------- 6939SELECT GEN_ID(GEN_NUM, 1) FROM RDB$DATABASE 6940 13 ms 6941 6942""" 6943 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6944EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6945SQLInfo(sql_id=1, sql='SELECT GEN_ID(GEN_NUM, 1) FROM RDB$DATABASE', plan=None) 6946EventPrepareStatement(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, statement_id=181, sql_id=1, prepare_time=13) 6947""" 6948 self._check_events(trace_lines, output) 6949 def test_prepare_statement_no_attachment(self): 6950 trace_lines = """2014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 6951 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6952 /opt/firebird/bin/isql:8723 6953 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6954 69552014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) PREPARE_STATEMENT 6956 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6957 /opt/firebird/bin/isql:8723 6958 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6959 6960Statement 181: 6961------------------------------------------------------------------------------- 6962SELECT GEN_ID(GEN_NUM, 1) FROM RDB$DATABASE 6963^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6964PLAN (RDB$DATABASE NATURAL) 6965 13 ms 6966 6967""" 6968 output = """AttachmentInfo(attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6969EventTransactionStart(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6970SQLInfo(sql_id=1, sql='SELECT GEN_ID(GEN_NUM, 1) FROM RDB$DATABASE', plan='PLAN (RDB$DATABASE NATURAL)') 6971EventPrepareStatement(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, statement_id=181, sql_id=1, prepare_time=13) 6972""" 6973 self._check_events(trace_lines, output) 6974 def test_prepare_statement_no_transaction(self): 6975 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 6976 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6977 /opt/firebird/bin/isql:8723 6978 69792014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) PREPARE_STATEMENT 6980 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 6981 /opt/firebird/bin/isql:8723 6982 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 6983 6984Statement 181: 6985------------------------------------------------------------------------------- 6986SELECT GEN_ID(GEN_NUM, 1) FROM RDB$DATABASE 6987^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6988PLAN (RDB$DATABASE NATURAL) 6989 13 ms 6990 6991""" 6992 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 6993TransactionInfo(attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 6994SQLInfo(sql_id=1, sql='SELECT GEN_ID(GEN_NUM, 1) FROM RDB$DATABASE', plan='PLAN (RDB$DATABASE NATURAL)') 6995EventPrepareStatement(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, statement_id=181, sql_id=1, prepare_time=13) 6996""" 6997 self._check_events(trace_lines, output) 6998 def test_prepare_statement_no_attachment_no_transaction(self): 6999 trace_lines = """2014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) PREPARE_STATEMENT 7000 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7001 /opt/firebird/bin/isql:8723 7002 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7003 7004Statement 181: 7005------------------------------------------------------------------------------- 7006SELECT GEN_ID(GEN_NUM, 1) FROM RDB$DATABASE 7007^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7008PLAN (RDB$DATABASE NATURAL) 7009 13 ms 7010 7011""" 7012 output = """AttachmentInfo(attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7013TransactionInfo(attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7014SQLInfo(sql_id=1, sql='SELECT GEN_ID(GEN_NUM, 1) FROM RDB$DATABASE', plan='PLAN (RDB$DATABASE NATURAL)') 7015EventPrepareStatement(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, statement_id=181, sql_id=1, prepare_time=13) 7016""" 7017 self._check_events(trace_lines, output) 7018 def test_statement_start(self): 7019 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7020 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7021 /opt/firebird/bin/isql:8723 7022 70232014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7024 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7025 /opt/firebird/bin/isql:8723 7026 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7027 70282014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_START 7029 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7030 /opt/firebird/bin/isql:8723 7031 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7032 7033Statement 166353: 7034------------------------------------------------------------------------------- 7035UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=? 7036 7037^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7038PLAN (TABLE_A INDEX (TABLE_A_PK)) 7039 7040param0 = timestamp, "2017-11-09T11:23:52.1570" 7041param1 = integer, "100012829" 7042param2 = integer, "<NULL>" 7043param3 = varchar(20), "2810090906551" 7044param4 = integer, "4199300" 7045""" 7046 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7047EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7048ParamInfo(par_id=1, params=[('timestamp', datetime.datetime(2017, 11, 9, 11, 23, 52, 157000)), ('integer', 100012829), ('integer', None), ('varchar(20)', '2810090906551'), ('integer', 4199300)]) 7049SQLInfo(sql_id=1, sql='UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=?', plan='PLAN (TABLE_A INDEX (TABLE_A_PK))') 7050EventStatementStart(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, statement_id=166353, sql_id=1, param_id=1) 7051""" 7052 self._check_events(trace_lines, output) 7053 def test_statement_start_no_plan(self): 7054 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7055 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7056 /opt/firebird/bin/isql:8723 7057 70582014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7059 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7060 /opt/firebird/bin/isql:8723 7061 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7062 70632014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_START 7064 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7065 /opt/firebird/bin/isql:8723 7066 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7067 7068Statement 166353: 7069------------------------------------------------------------------------------- 7070UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=? 7071param0 = timestamp, "2017-11-09T11:23:52.1570" 7072param1 = integer, "100012829" 7073param2 = integer, "<NULL>" 7074param3 = varchar(20), "2810090906551" 7075param4 = integer, "4199300" 7076""" 7077 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7078EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7079ParamInfo(par_id=1, params=[('timestamp', datetime.datetime(2017, 11, 9, 11, 23, 52, 157000)), ('integer', 100012829), ('integer', None), ('varchar(20)', '2810090906551'), ('integer', 4199300)]) 7080SQLInfo(sql_id=1, sql='UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=?', plan=None) 7081EventStatementStart(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, statement_id=166353, sql_id=1, param_id=1) 7082""" 7083 self._check_events(trace_lines, output) 7084 def test_statement_start_no_attachment(self): 7085 trace_lines = """2014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7086 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7087 /opt/firebird/bin/isql:8723 7088 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7089 70902014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_START 7091 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7092 /opt/firebird/bin/isql:8723 7093 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7094 7095Statement 166353: 7096------------------------------------------------------------------------------- 7097UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=? 7098 7099^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7100PLAN (TABLE_A INDEX (TABLE_A_PK)) 7101 7102param0 = timestamp, "2017-11-09T11:23:52.1570" 7103param1 = integer, "100012829" 7104param2 = integer, "<NULL>" 7105param3 = varchar(20), "2810090906551" 7106param4 = integer, "4199300" 7107""" 7108 output = """AttachmentInfo(attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7109EventTransactionStart(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7110ParamInfo(par_id=1, params=[('timestamp', datetime.datetime(2017, 11, 9, 11, 23, 52, 157000)), ('integer', 100012829), ('integer', None), ('varchar(20)', '2810090906551'), ('integer', 4199300)]) 7111SQLInfo(sql_id=1, sql='UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=?', plan='PLAN (TABLE_A INDEX (TABLE_A_PK))') 7112EventStatementStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, statement_id=166353, sql_id=1, param_id=1) 7113""" 7114 self._check_events(trace_lines, output) 7115 def test_statement_start_no_transaction(self): 7116 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7117 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7118 /opt/firebird/bin/isql:8723 7119 71202014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_START 7121 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7122 /opt/firebird/bin/isql:8723 7123 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7124 7125Statement 166353: 7126------------------------------------------------------------------------------- 7127UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=? 7128 7129^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7130PLAN (TABLE_A INDEX (TABLE_A_PK)) 7131 7132param0 = timestamp, "2017-11-09T11:23:52.1570" 7133param1 = integer, "100012829" 7134param2 = integer, "<NULL>" 7135param3 = varchar(20), "2810090906551" 7136param4 = integer, "4199300" 7137""" 7138 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7139TransactionInfo(attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7140ParamInfo(par_id=1, params=[('timestamp', datetime.datetime(2017, 11, 9, 11, 23, 52, 157000)), ('integer', 100012829), ('integer', None), ('varchar(20)', '2810090906551'), ('integer', 4199300)]) 7141SQLInfo(sql_id=1, sql='UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=?', plan='PLAN (TABLE_A INDEX (TABLE_A_PK))') 7142EventStatementStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, statement_id=166353, sql_id=1, param_id=1) 7143""" 7144 self._check_events(trace_lines, output) 7145 def test_statement_start_no_attachment_no_transaction(self): 7146 trace_lines = """2014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_START 7147 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7148 /opt/firebird/bin/isql:8723 7149 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7150 7151Statement 166353: 7152------------------------------------------------------------------------------- 7153UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=? 7154 7155^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7156PLAN (TABLE_A INDEX (TABLE_A_PK)) 7157 7158param0 = timestamp, "2017-11-09T11:23:52.1570" 7159param1 = integer, "100012829" 7160param2 = integer, "<NULL>" 7161param3 = varchar(20), "2810090906551" 7162param4 = integer, "4199300" 7163""" 7164 output = """AttachmentInfo(attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7165TransactionInfo(attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7166ParamInfo(par_id=1, params=[('timestamp', datetime.datetime(2017, 11, 9, 11, 23, 52, 157000)), ('integer', 100012829), ('integer', None), ('varchar(20)', '2810090906551'), ('integer', 4199300)]) 7167SQLInfo(sql_id=1, sql='UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=?', plan='PLAN (TABLE_A INDEX (TABLE_A_PK))') 7168EventStatementStart(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, statement_id=166353, sql_id=1, param_id=1) 7169""" 7170 self._check_events(trace_lines, output) 7171 def test_statement_finish(self): 7172 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7173 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7174 /opt/firebird/bin/isql:8723 7175 71762014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7177 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7178 /opt/firebird/bin/isql:8723 7179 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7180 71812014-05-23T11:00:45.5420 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_FINISH 7182 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7183 /opt/firebird/bin/isql:8723 7184 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7185 7186Statement 181: 7187------------------------------------------------------------------------------- 7188SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE 7189^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7190PLAN (RDB$DATABASE NATURAL) 71911 records fetched 7192 0 ms, 2 read(s), 14 fetch(es), 1 mark(s) 7193 7194Table Natural Index Update Insert Delete Backout Purge Expunge 7195*************************************************************************************************************** 7196RDB$DATABASE 1 7197RDB$CHARACTER_SETS 1 7198RDB$COLLATIONS 1 7199""" 7200 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7201EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7202SQLInfo(sql_id=1, sql='SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE', plan='PLAN (RDB$DATABASE NATURAL)') 7203EventStatementFinish(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 542000), status=' ', attachment_id=8, transaction_id=1570, statement_id=181, sql_id=1, param_id=None, records=1, run_time=0, reads=2, writes=None, fetches=14, marks=1, access=[AccessTuple(table='RDB$DATABASE', natural=1, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$CHARACTER_SETS', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$COLLATIONS', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 7204""" 7205 self._check_events(trace_lines, output) 7206 def test_statement_finish_no_plan(self): 7207 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7208 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7209 /opt/firebird/bin/isql:8723 7210 72112014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7212 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7213 /opt/firebird/bin/isql:8723 7214 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7215 72162014-05-23T11:00:45.5420 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_FINISH 7217 /home/employee.fdb (ATT_8, EUROFLOW:NONE, ISO88591, TCPv4:192.168.1.5) 7218 /opt/firebird/bin/isql:8723 7219 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7220 7221Statement 181: 7222------------------------------------------------------------------------------- 7223SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE 72241 records fetched 7225 0 ms, 2 read(s), 14 fetch(es), 1 mark(s) 7226 7227Table Natural Index Update Insert Delete Backout Purge Expunge 7228*************************************************************************************************************** 7229RDB$DATABASE 1 7230RDB$CHARACTER_SETS 1 7231RDB$COLLATIONS 1 7232""" 7233 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7234EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7235SQLInfo(sql_id=1, sql='SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE', plan=None) 7236EventStatementFinish(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 542000), status=' ', attachment_id=8, transaction_id=1570, statement_id=181, sql_id=1, param_id=None, records=1, run_time=0, reads=2, writes=None, fetches=14, marks=1, access=[AccessTuple(table='RDB$DATABASE', natural=1, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$CHARACTER_SETS', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$COLLATIONS', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 7237""" 7238 self._check_events(trace_lines, output) 7239 def test_statement_finish_no_attachment(self): 7240 trace_lines = """2014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7241 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7242 /opt/firebird/bin/isql:8723 7243 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7244 72452014-05-23T11:00:45.5420 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_FINISH 7246 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7247 /opt/firebird/bin/isql:8723 7248 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7249 7250Statement 181: 7251------------------------------------------------------------------------------- 7252SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE 7253^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7254PLAN (RDB$DATABASE NATURAL) 72551 records fetched 7256 0 ms, 2 read(s), 14 fetch(es), 1 mark(s) 7257 7258Table Natural Index Update Insert Delete Backout Purge Expunge 7259*************************************************************************************************************** 7260RDB$DATABASE 1 7261RDB$CHARACTER_SETS 1 7262RDB$COLLATIONS 1 7263""" 7264 output = """AttachmentInfo(attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7265EventTransactionStart(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7266SQLInfo(sql_id=1, sql='SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE', plan='PLAN (RDB$DATABASE NATURAL)') 7267EventStatementFinish(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 542000), status=' ', attachment_id=8, transaction_id=1570, statement_id=181, sql_id=1, param_id=None, records=1, run_time=0, reads=2, writes=None, fetches=14, marks=1, access=[AccessTuple(table='RDB$DATABASE', natural=1, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$CHARACTER_SETS', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$COLLATIONS', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 7268""" 7269 self._check_events(trace_lines, output) 7270 def test_statement_finish_no_transaction(self): 7271 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7272 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7273 /opt/firebird/bin/isql:8723 7274 72752014-05-23T11:00:45.5420 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_FINISH 7276 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7277 /opt/firebird/bin/isql:8723 7278 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7279 7280Statement 181: 7281------------------------------------------------------------------------------- 7282SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE 7283^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7284PLAN (RDB$DATABASE NATURAL) 72851 records fetched 7286 0 ms, 2 read(s), 14 fetch(es), 1 mark(s) 7287 7288Table Natural Index Update Insert Delete Backout Purge Expunge 7289*************************************************************************************************************** 7290RDB$DATABASE 1 7291RDB$CHARACTER_SETS 1 7292RDB$COLLATIONS 1 7293""" 7294 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7295TransactionInfo(attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7296SQLInfo(sql_id=1, sql='SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE', plan='PLAN (RDB$DATABASE NATURAL)') 7297EventStatementFinish(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 542000), status=' ', attachment_id=8, transaction_id=1570, statement_id=181, sql_id=1, param_id=None, records=1, run_time=0, reads=2, writes=None, fetches=14, marks=1, access=[AccessTuple(table='RDB$DATABASE', natural=1, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$CHARACTER_SETS', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$COLLATIONS', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 7298""" 7299 self._check_events(trace_lines, output) 7300 def test_statement_finish_no_attachment_no_transaction(self): 7301 trace_lines = """2014-05-23T11:00:45.5420 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_FINISH 7302 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7303 /opt/firebird/bin/isql:8723 7304 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7305 7306Statement 181: 7307------------------------------------------------------------------------------- 7308SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE 7309^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7310PLAN (RDB$DATABASE NATURAL) 73111 records fetched 7312 0 ms, 2 read(s), 14 fetch(es), 1 mark(s) 7313 7314Table Natural Index Update Insert Delete Backout Purge Expunge 7315*************************************************************************************************************** 7316RDB$DATABASE 1 7317RDB$CHARACTER_SETS 1 7318RDB$COLLATIONS 1 7319""" 7320 output = """AttachmentInfo(attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7321TransactionInfo(attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7322SQLInfo(sql_id=1, sql='SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE', plan='PLAN (RDB$DATABASE NATURAL)') 7323EventStatementFinish(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 542000), status=' ', attachment_id=8, transaction_id=1570, statement_id=181, sql_id=1, param_id=None, records=1, run_time=0, reads=2, writes=None, fetches=14, marks=1, access=[AccessTuple(table='RDB$DATABASE', natural=1, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$CHARACTER_SETS', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$COLLATIONS', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 7324""" 7325 self._check_events(trace_lines, output) 7326 def test_statement_finish_no_performance(self): 7327 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7328 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7329 /opt/firebird/bin/isql:8723 7330 73312014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7332 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7333 /opt/firebird/bin/isql:8723 7334 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7335 73362014-05-23T11:00:45.5420 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_FINISH 7337 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7338 /opt/firebird/bin/isql:8723 7339 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7340 7341Statement 181: 7342------------------------------------------------------------------------------- 7343SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE 7344^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7345PLAN (RDB$DATABASE NATURAL) 7346""" 7347 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7348EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7349SQLInfo(sql_id=1, sql='SELECT GEN_ID(GEN_NUM, 1) NUMS FROM RDB$DATABASE', plan='PLAN (RDB$DATABASE NATURAL)') 7350EventStatementFinish(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 542000), status=' ', attachment_id=8, transaction_id=1570, statement_id=181, sql_id=1, param_id=None, records=None, run_time=None, reads=None, writes=None, fetches=None, marks=None, access=None) 7351""" 7352 self._check_events(trace_lines, output) 7353 def test_statement_free(self): 7354 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7355 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7356 /opt/firebird/bin/isql:8723 7357 73582014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7359 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7360 /opt/firebird/bin/isql:8723 7361 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7362 73632014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) FREE_STATEMENT 7364 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7365 /opt/firebird/bin/isql:8723 7366 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7367 7368Statement 166353: 7369------------------------------------------------------------------------------- 7370UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=? 7371^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7372PLAN (TABLE_A INDEX (TABLE_A_PK)) 7373""" 7374 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7375EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7376SQLInfo(sql_id=1, sql='UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=?', plan='PLAN (TABLE_A INDEX (TABLE_A_PK))') 7377EventFreeStatement(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), attachment_id=8, transaction_id=1570, statement_id=166353, sql_id=1) 7378""" 7379 self._check_events(trace_lines, output) 7380 def test_close_cursor(self): 7381 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7382 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7383 /opt/firebird/bin/isql:8723 7384 73852014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7386 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7387 /opt/firebird/bin/isql:8723 7388 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7389 73902014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) CLOSE_CURSOR 7391 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7392 /opt/firebird/bin/isql:8723 7393 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7394 7395Statement 166353: 7396------------------------------------------------------------------------------- 7397UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=? 7398^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7399PLAN (TABLE_A INDEX (TABLE_A_PK)) 7400""" 7401 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7402EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7403SQLInfo(sql_id=1, sql='UPDATE TABLE_A SET VAL_1=?, VAL_2=?, VAL_3=?, VAL_4=? WHERE ID_EX=?', plan='PLAN (TABLE_A INDEX (TABLE_A_PK))') 7404EventCloseCursor(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), attachment_id=8, transaction_id=1570, statement_id=166353, sql_id=1) 7405""" 7406 self._check_events(trace_lines, output) 7407 def test_trigger_start(self): 7408 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7409 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7410 /opt/firebird/bin/isql:8723 7411 74122014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7413 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7414 /opt/firebird/bin/isql:8723 7415 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7416 74172014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) EXECUTE_TRIGGER_START 7418 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7419 /opt/firebird/bin/isql:8723 7420 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7421 BI_TABLE_A FOR TABLE_A (BEFORE INSERT) 7422""" 7423 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7424EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7425EventTriggerStart(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, trigger='BI_TABLE_A', table='TABLE_A', event='BEFORE INSERT') 7426""" 7427 self._check_events(trace_lines, output) 7428 def test_trigger_finish(self): 7429 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7430 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7431 /opt/firebird/bin/isql:8723 7432 74332014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7434 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7435 /opt/firebird/bin/isql:8723 7436 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7437 74382014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) EXECUTE_TRIGGER_FINISH 7439 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7440 /opt/firebird/bin/isql:8723 7441 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7442 AIU_TABLE_A FOR TABLE_A (AFTER INSERT) 7443 1118 ms, 681 read(s), 80 write(s), 1426 fetch(es), 80 mark(s) 7444 7445Table Natural Index Update Insert Delete Backout Purge Expunge 7446*************************************************************************************************************** 7447RDB$DATABASE 1 7448RDB$INDICES 107 7449RDB$RELATIONS 10 7450RDB$FORMATS 6 7451RDB$RELATION_CONSTRAINTS 20 7452TABLE_A 1 7453TABLE_B 2 7454TABLE_C 1 7455TABLE_D 1 7456TABLE_E 3 7457TABLE_F 25 7458""" 7459 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7460EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7461EventTriggerFinish(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, trigger='AIU_TABLE_A', table='TABLE_A', event='AFTER INSERT', run_time=1118, reads=681, writes=80, fetches=1426, marks=80, access=[AccessTuple(table='RDB$DATABASE', natural=1, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$INDICES', natural=0, index=107, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$RELATIONS', natural=0, index=10, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$FORMATS', natural=0, index=6, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='RDB$RELATION_CONSTRAINTS', natural=0, index=20, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='TABLE_A', natural=0, index=0, update=0, insert=1, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='TABLE_B', natural=0, index=2, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='TABLE_C', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='TABLE_D', natural=0, index=0, update=0, insert=1, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='TABLE_E', natural=0, index=3, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='TABLE_F', natural=0, index=25, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 7462""" 7463 self._check_events(trace_lines, output) 7464 def test_procedure_start(self): 7465 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7466 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7467 /opt/firebird/bin/isql:8723 7468 74692014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7470 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7471 /opt/firebird/bin/isql:8723 7472 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7473 74742014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) EXECUTE_PROCEDURE_START 7475 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7476 /opt/firebird/bin/isql:8723 7477 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7478 7479Procedure PROC_A: 7480param0 = varchar(50), "758749" 7481param1 = varchar(10), "XXX" 7482""" 7483 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7484EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7485ParamInfo(par_id=1, params=[('varchar(50)', '758749'), ('varchar(10)', 'XXX')]) 7486EventProcedureStart(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, procedure='PROC_A', param_id=1) 7487""" 7488 self._check_events(trace_lines, output) 7489 def test_procedure_finish(self): 7490 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7491 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7492 /opt/firebird/bin/isql:8723 7493 74942014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7495 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7496 /opt/firebird/bin/isql:8723 7497 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7498 74992014-05-23T11:00:45.5260 (3720:0000000000EFD9E8) EXECUTE_PROCEDURE_FINISH 7500 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7501 /opt/firebird/bin/isql:8723 7502 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7503 7504Procedure PROC_A: 7505param0 = varchar(10), "XXX" 7506param1 = double precision, "313204" 7507param2 = double precision, "1" 7508param3 = varchar(20), "50031" 7509param4 = varchar(20), "GGG(1.25)" 7510param5 = varchar(10), "PP100X120" 7511param6 = varchar(20), "<NULL>" 7512param7 = double precision, "3.33333333333333" 7513param8 = double precision, "45" 7514param9 = integer, "3" 7515param10 = integer, "<NULL>" 7516param11 = double precision, "1" 7517param12 = integer, "0" 7518 7519 0 ms, 14 read(s), 14 fetch(es) 7520 7521Table Natural Index Update Insert Delete Backout Purge Expunge 7522*************************************************************************************************************** 7523TABLE_A 1 7524TABLE_B 1 7525""" 7526 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7527EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7528ParamInfo(par_id=1, params=[('varchar(10)', 'XXX'), ('double precision', Decimal('313204')), ('double precision', Decimal('1')), ('varchar(20)', '50031'), ('varchar(20)', 'GGG(1.25)'), ('varchar(10)', 'PP100X120'), ('varchar(20)', None), ('double precision', Decimal('3.33333333333333')), ('double precision', Decimal('45')), ('integer', 3), ('integer', None), ('double precision', Decimal('1')), ('integer', 0)]) 7529EventProcedureFinish(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 45, 526000), status=' ', attachment_id=8, transaction_id=1570, procedure='PROC_A', param_id=1, run_time=0, reads=14, writes=None, fetches=14, marks=None, access=[AccessTuple(table='TABLE_A', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0), AccessTuple(table='TABLE_B', natural=0, index=1, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 7530""" 7531 self._check_events(trace_lines, output) 7532 def test_service_attach(self): 7533 trace_lines = """2017-11-13T11:49:51.3110 (2500:0000000026C3C858) ATTACH_SERVICE 7534 service_mgr, (Service 0000000019993DC0, SYSDBA, TCPv4:127.0.0.1, /job/fbtrace:385) 7535""" 7536 output = """ServiceInfo(service_id=429473216, user='SYSDBA', protocol='TCPv4', address='127.0.0.1', remote_process='/job/fbtrace', remote_pid=385) 7537EventServiceAttach(event_id=1, timestamp=datetime.datetime(2017, 11, 13, 11, 49, 51, 311000), status=' ', service_id=429473216) 7538""" 7539 self._check_events(trace_lines, output) 7540 def test_service_detach(self): 7541 trace_lines = """2017-11-13T22:50:09.3790 (2500:0000000026C39D70) DETACH_SERVICE 7542 service_mgr, (Service 0000000028290058, SYSDBA, TCPv4:127.0.0.1, /job/fbtrace:385) 7543""" 7544 output = """ServiceInfo(service_id=673775704, user='SYSDBA', protocol='TCPv4', address='127.0.0.1', remote_process='/job/fbtrace', remote_pid=385) 7545EventServiceDetach(event_id=1, timestamp=datetime.datetime(2017, 11, 13, 22, 50, 9, 379000), status=' ', service_id=673775704) 7546""" 7547 self._check_events(trace_lines, output) 7548 def test_service_start(self): 7549 trace_lines = """2017-11-13T11:49:07.7860 (2500:0000000001A4DB68) START_SERVICE 7550 service_mgr, (Service 000000001F6F1CF8, SYSDBA, TCPv4:127.0.0.1, /job/fbtrace:385) 7551 "Start Trace Session" 7552 -TRUSTED_SVC SYSDBA -START -CONFIG <database %[\\/]TEST.FDB> 7553enabled true 7554log_connections true 7555log_transactions true 7556log_statement_prepare false 7557log_statement_free false 7558log_statement_start false 7559log_statement_finish false 7560print_plan false 7561print_perf false 7562time_threshold 1000 7563max_sql_length 300 7564max_arg_length 80 7565max_arg_count 30 7566log_procedure_start false 7567log_procedure_finish false 7568log_trigger_start false 7569log_trigger_finish false 7570log_context false 7571log_errors false 7572log_sweep false 7573log_blr_requests false 7574print_blr false 7575max_blr_length 500 7576log_dyn_requests false 7577print_dyn false 7578max_dyn_length 500 7579log_warnings false 7580log_initfini false 7581</database> 7582 7583<services> 7584enabled true 7585log_services true 7586log_errors false 7587log_warnings false 7588log_initfini false 7589</services> 7590""" 7591 output = """ServiceInfo(service_id=527375608, user='SYSDBA', protocol='TCPv4', address='127.0.0.1', remote_process='/job/fbtrace', remote_pid=385) 7592EventServiceStart(event_id=1, timestamp=datetime.datetime(2017, 11, 13, 11, 49, 7, 786000), status=' ', service_id=527375608, action='Start Trace Session', parameters=['-TRUSTED_SVC SYSDBA -START -CONFIG <database %[\\\\/]TEST.FDB>', 'enabled true', 'log_connections true', 'log_transactions true', 'log_statement_prepare false', 'log_statement_free false', 'log_statement_start false', 'log_statement_finish false', 'print_plan false', 'print_perf false', 'time_threshold 1000', 'max_sql_length 300', 'max_arg_length 80', 'max_arg_count 30', 'log_procedure_start false', 'log_procedure_finish false', 'log_trigger_start false', 'log_trigger_finish false', 'log_context false', 'log_errors false', 'log_sweep false', 'log_blr_requests false', 'print_blr false', 'max_blr_length 500', 'log_dyn_requests false', 'print_dyn false', 'max_dyn_length 500', 'log_warnings false', 'log_initfini false', '</database>', '<services>', 'enabled true', 'log_services true', 'log_errors false', 'log_warnings false', 'log_initfini false', '</services>']) 7593""" 7594 self._check_events(trace_lines, output) 7595 def test_service_query(self): 7596 trace_lines = """2018-03-29T14:02:10.9180 (5924:0x7feab93f4978) QUERY_SERVICE 7597 service_mgr, (Service 0x7feabd3da548, SYSDBA, TCPv4:127.0.0.1, /job/fbtrace:385) 7598 "Start Trace Session" 7599 Receive portion of the query: 7600 retrieve 1 line of service output per call 7601 76022018-04-03T12:41:01.7970 (5831:0x7f748c054978) QUERY_SERVICE 7603 service_mgr, (Service 0x7f748f839540, SYSDBA, TCPv4:127.0.0.1, /job/fbtrace:4631) 7604 Receive portion of the query: 7605 retrieve the version of the server engine 7606 76072018-04-03T12:41:30.7840 (5831:0x7f748c054978) QUERY_SERVICE 7608 service_mgr, (Service 0x7f748f839540, SYSDBA, TCPv4:127.0.0.1, /job/fbtrace:4631) 7609 Receive portion of the query: 7610 retrieve the implementation of the Firebird server 7611 76122018-04-03T12:56:27.5590 (5831:0x7f748c054978) QUERY_SERVICE 7613 service_mgr, (Service 0x7f748f839540, SYSDBA, TCPv4:127.0.0.1, /job/fbtrace:4631) 7614 "Repair Database" 7615""" 7616 output = """ServiceInfo(service_id=140646174008648, user='SYSDBA', protocol='TCPv4', address='127.0.0.1', remote_process='/job/fbtrace', remote_pid=385) 7617EventServiceQuery(event_id=1, timestamp=datetime.datetime(2018, 3, 29, 14, 2, 10, 918000), status=' ', service_id=140646174008648, action='Start Trace Session', parameters=['Receive portion of the query:', 'retrieve 1 line of service output per call']) 7618ServiceInfo(service_id=140138600699200, user='SYSDBA', protocol='TCPv4', address='127.0.0.1', remote_process='/job/fbtrace', remote_pid=4631) 7619EventServiceQuery(event_id=2, timestamp=datetime.datetime(2018, 4, 3, 12, 41, 1, 797000), status=' ', service_id=140138600699200, action=None, parameters=['retrieve the version of the server engine']) 7620EventServiceQuery(event_id=3, timestamp=datetime.datetime(2018, 4, 3, 12, 41, 30, 784000), status=' ', service_id=140138600699200, action=None, parameters=['retrieve the implementation of the Firebird server']) 7621EventServiceQuery(event_id=4, timestamp=datetime.datetime(2018, 4, 3, 12, 56, 27, 559000), status=' ', service_id=140138600699200, action='Repair Database', parameters=[]) 7622""" 7623 if sys.version_info.major == 2 and sys.version_info.minor == 7 and sys.version_info.micro > 13: 7624 output = """ServiceInfo(service_id=140646174008648, user='SYSDBA', protocol='TCPv4', address='127.0.0.1', remote_process='/job/fbtrace', remote_pid=385) 7625EventServiceQuery(event_id=1, timestamp=datetime.datetime(2018, 3, 29, 14, 2, 10, 918000), status=' ', service_id=140646174008648, action='Start Trace Session', parameters=['Receive portion of the query:', 'retrieve 1 line of service output per call']) 7626ServiceInfo(service_id=140138600699200, user='SYSDBA', protocol='TCPv4', address='127.0.0.1', remote_process='/job/fbtrace', remote_pid=4631) 7627EventServiceQuery(event_id=2, timestamp=datetime.datetime(2018, 4, 3, 12, 41, 1, 797000), status=' ', service_id=140138600699200, action=None, parameters=['retrieve the version of the server engine']) 7628EventServiceQuery(event_id=3, timestamp=datetime.datetime(2018, 4, 3, 12, 41, 30, 784000), status=' ', service_id=140138600699200, action=None, parameters=['retrieve the implementation of the Firebird server']) 7629EventServiceQuery(event_id=4, timestamp=datetime.datetime(2018, 4, 3, 12, 56, 27, 559000), status=' ', service_id=140138600699200, action='Repair Database', parameters=[]) 7630""" 7631 self._check_events(trace_lines, output) 7632 def test_set_context(self): 7633 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE 7634 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7635 /opt/firebird/bin/isql:8723 7636 76372014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION 7638 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7639 /opt/firebird/bin/isql:8723 7640 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7641 76422017-11-09T11:21:59.0270 (2500:0000000001A45B00) SET_CONTEXT 7643 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7644 /opt/firebird/bin/isql:8723 7645 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7646[USER_TRANSACTION] TRANSACTION_TIMESTAMP = "2017-11-09 11:21:59.0270" 7647 76482017-11-09T11:21:59.0300 (2500:0000000001A45B00) SET_CONTEXT 7649 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 7650 /opt/firebird/bin/isql:8723 7651 (TRA_1570, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) 7652[USER_SESSION] MY_KEY = "1" 7653""" 7654 output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=' ', attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7655EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=' ', attachment_id=8, transaction_id=1570, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) 7656EventSetContext(event_id=3, timestamp=datetime.datetime(2017, 11, 9, 11, 21, 59, 27000), attachment_id=8, transaction_id=1570, context='USER_TRANSACTION', key='TRANSACTION_TIMESTAMP', value='"2017-11-09 11:21:59.0270"') 7657EventSetContext(event_id=4, timestamp=datetime.datetime(2017, 11, 9, 11, 21, 59, 30000), attachment_id=8, transaction_id=1570, context='USER_SESSION', key='MY_KEY', value='"1"') 7658""" 7659 self._check_events(trace_lines, output) 7660 def test_error(self): 7661 trace_lines = """2018-03-22T10:06:59.5090 (4992:0x7f92a22a4978) ERROR AT jrd8_attach_database 7662 /home/test.fdb (ATT_0, sysdba, NONE, TCPv4:127.0.0.1) 7663 /usr/bin/flamerobin:4985 7664335544344 : I/O error during "open" operation for file "/home/test.fdb" 7665335544734 : Error while trying to open file 7666 2 : No such file or directory 7667 76682018-03-22T11:00:59.5090 (2500:0000000022415DB8) ERROR AT jrd8_fetch 7669 /home/test.fdb (ATT_519417, SYSDBA:NONE, WIN1250, TCPv4:172.19.54.61) 7670 /usr/bin/flamerobin:4985 7671335544364 : request synchronization error 7672 76732018-04-03T12:49:28.5080 (5831:0x7f748c054978) ERROR AT jrd8_service_query 7674 service_mgr, (Service 0x7f748f839540, SYSDBA, TCPv4:127.0.0.1, /job/fbtrace:4631) 7675335544344 : I/O error during "open" operation for file "bug.fdb" 7676335544734 : Error while trying to open file 7677 2 : No such file or directory 7678""" 7679 output = """AttachmentInfo(attachment_id=0, database='/home/test.fdb', charset='NONE', protocol='TCPv4', address='127.0.0.1', user='sysdba', role='NONE', remote_process='/usr/bin/flamerobin', remote_pid=4985) 7680EventError(event_id=1, timestamp=datetime.datetime(2018, 3, 22, 10, 6, 59, 509000), attachment_id=0, place='jrd8_attach_database', details=['335544344 : I/O error during "open" operation for file "/home/test.fdb"', '335544734 : Error while trying to open file', '2 : No such file or directory']) 7681AttachmentInfo(attachment_id=519417, database='/home/test.fdb', charset='WIN1250', protocol='TCPv4', address='172.19.54.61', user='SYSDBA', role='NONE', remote_process='/usr/bin/flamerobin', remote_pid=4985) 7682EventError(event_id=2, timestamp=datetime.datetime(2018, 3, 22, 11, 0, 59, 509000), attachment_id=519417, place='jrd8_fetch', details=['335544364 : request synchronization error']) 7683ServiceInfo(service_id=140138600699200, user='SYSDBA', protocol='TCPv4', address='127.0.0.1', remote_process='/job/fbtrace', remote_pid=4631) 7684EventServiceError(event_id=3, timestamp=datetime.datetime(2018, 4, 3, 12, 49, 28, 508000), service_id=140138600699200, place='jrd8_service_query', details=['335544344 : I/O error during "open" operation for file "bug.fdb"', '335544734 : Error while trying to open file', '2 : No such file or directory']) 7685""" 7686 if sys.version_info.major == 2 and sys.version_info.minor == 7 and sys.version_info.micro > 13: 7687 output = """AttachmentInfo(attachment_id=0, database='/home/test.fdb', charset='NONE', protocol='TCPv4', address='127.0.0.1', user='sysdba', role='NONE', remote_process='/usr/bin/flamerobin', remote_pid=4985) 7688EventError(event_id=1, timestamp=datetime.datetime(2018, 3, 22, 10, 6, 59, 509000), attachment_id=0, place='jrd8_attach_database', details=['335544344 : I/O error during "open" operation for file "/home/test.fdb"', '335544734 : Error while trying to open file', '2 : No such file or directory']) 7689AttachmentInfo(attachment_id=519417, database='/home/test.fdb', charset='WIN1250', protocol='TCPv4', address='172.19.54.61', user='SYSDBA', role='NONE', remote_process='/usr/bin/flamerobin', remote_pid=4985) 7690EventError(event_id=2, timestamp=datetime.datetime(2018, 3, 22, 11, 0, 59, 509000), attachment_id=519417, place='jrd8_fetch', details=['335544364 : request synchronization error']) 7691ServiceInfo(service_id=140138600699200, user='SYSDBA', protocol='TCPv4', address='127.0.0.1', remote_process='/job/fbtrace', remote_pid=4631) 7692EventServiceError(event_id=3, timestamp=datetime.datetime(2018, 4, 3, 12, 49, 28, 508000), service_id=140138600699200, place='jrd8_service_query', details=['335544344 : I/O error during "open" operation for file "bug.fdb"', '335544734 : Error while trying to open file', '2 : No such file or directory']) 7693""" 7694 self._check_events(trace_lines, output) 7695 def test_warning(self): 7696 trace_lines = """2018-03-22T10:06:59.5090 (4992:0x7f92a22a4978) WARNING AT jrd8_attach_database 7697 /home/test.fdb (ATT_0, sysdba, NONE, TCPv4:127.0.0.1) 7698 /usr/bin/flamerobin:4985 7699Some reason for the warning. 7700 77012018-04-03T12:49:28.5080 (5831:0x7f748c054978) WARNING AT jrd8_service_query 7702 service_mgr, (Service 0x7f748f839540, SYSDBA, TCPv4:127.0.0.1, /job/fbtrace:4631) 7703Some reason for the warning. 7704""" 7705 output = """AttachmentInfo(attachment_id=0, database='/home/test.fdb', charset='NONE', protocol='TCPv4', address='127.0.0.1', user='sysdba', role='NONE', remote_process='/usr/bin/flamerobin', remote_pid=4985) 7706EventWarning(event_id=1, timestamp=datetime.datetime(2018, 3, 22, 10, 6, 59, 509000), attachment_id=0, place='jrd8_attach_database', details=['Some reason for the warning.']) 7707ServiceInfo(service_id=140138600699200, user='SYSDBA', protocol='TCPv4', address='127.0.0.1', remote_process='/job/fbtrace', remote_pid=4631) 7708EventServiceWarning(event_id=2, timestamp=datetime.datetime(2018, 4, 3, 12, 49, 28, 508000), service_id=140138600699200, place='jrd8_service_query', details=['Some reason for the warning.']) 7709""" 7710 if sys.version_info.major == 2 and sys.version_info.minor == 7 and sys.version_info.micro > 13: 7711 output = """AttachmentInfo(attachment_id=0, database='/home/test.fdb', charset='NONE', protocol='TCPv4', address='127.0.0.1', user='sysdba', role='NONE', remote_process='/usr/bin/flamerobin', remote_pid=4985) 7712EventWarning(event_id=1, timestamp=datetime.datetime(2018, 3, 22, 10, 6, 59, 509000), attachment_id=0, place='jrd8_attach_database', details=['Some reason for the warning.']) 7713ServiceInfo(service_id=140138600699200, user='SYSDBA', protocol='TCPv4', address='127.0.0.1', remote_process='/job/fbtrace', remote_pid=4631) 7714EventServiceWarning(event_id=2, timestamp=datetime.datetime(2018, 4, 3, 12, 49, 28, 508000), service_id=140138600699200, place='jrd8_service_query', details=['Some reason for the warning.']) 7715""" 7716 self._check_events(trace_lines, output) 7717 def test_sweep_start(self): 7718 trace_lines = """2018-03-22T17:33:56.9690 (12351:0x7f0174bdd978) SWEEP_START 7719 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, TCPv4:127.0.0.1) 7720 7721Transaction counters: 7722 Oldest interesting 155 7723 Oldest active 156 7724 Oldest snapshot 156 7725 Next transaction 156 7726 77272018-03-22T18:33:56.9690 (12351:0x7f0174bdd978) SWEEP_START 7728 /opt/firebird/examples/empbuild/employee.fdb (ATT_9, SYSDBA:NONE, NONE, TCPv4:127.0.0.1) 7729 /opt/firebird/bin/isql:8723 7730 7731Transaction counters: 7732 Oldest interesting 155 7733 Oldest active 156 7734 Oldest snapshot 156 7735 Next transaction 156 7736""" 7737 output = """AttachmentInfo(attachment_id=8, database='/opt/firebird/examples/empbuild/employee.fdb', charset='NONE', protocol='TCPv4', address='127.0.0.1', user='SYSDBA', role='NONE', remote_process=None, remote_pid=None) 7738EventSweepStart(event_id=1, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 56, 969000), attachment_id=8, oit=155, oat=156, ost=156, next=156) 7739AttachmentInfo(attachment_id=9, database='/opt/firebird/examples/empbuild/employee.fdb', charset='NONE', protocol='TCPv4', address='127.0.0.1', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) 7740EventSweepStart(event_id=2, timestamp=datetime.datetime(2018, 3, 22, 18, 33, 56, 969000), attachment_id=9, oit=155, oat=156, ost=156, next=156) 7741""" 7742 self._check_events(trace_lines, output) 7743 def test_sweep_progress(self): 7744 trace_lines = """2018-03-22T17:33:56.9820 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7745 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7746 0 ms, 5 fetch(es) 7747 77482018-03-22T17:33:56.9830 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7749 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7750 0 ms, 6 read(s), 409 fetch(es) 7751 77522018-03-22T17:33:56.9920 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7753 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7754 9 ms, 5 read(s), 345 fetch(es), 39 mark(s) 7755 77562018-03-22T17:33:56.9930 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7757 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7758 0 ms, 4 read(s), 251 fetch(es), 24 mark(s) 7759 77602018-03-22T17:33:57.0000 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7761 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7762 7 ms, 14 read(s), 877 fetch(es), 4 mark(s) 7763 77642018-03-22T17:33:57.0000 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7765 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7766 0 ms, 2 read(s), 115 fetch(es) 7767 77682018-03-22T17:33:57.0000 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7769 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7770 0 ms, 2 read(s), 7 fetch(es) 7771 77722018-03-22T17:33:57.0020 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7773 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7774 1 ms, 2 read(s), 25 fetch(es) 7775 77762018-03-22T17:33:57.0070 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7777 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7778 5 ms, 4 read(s), 1 write(s), 339 fetch(es), 97 mark(s) 7779 77802018-03-22T17:33:57.0090 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7781 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7782 2 ms, 6 read(s), 1 write(s), 467 fetch(es) 7783 77842018-03-22T17:33:57.0100 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7785 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7786 0 ms, 2 read(s), 149 fetch(es) 7787 77882018-03-22T17:33:57.0930 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7789 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7790 83 ms, 11 read(s), 8 write(s), 2307 fetch(es), 657 mark(s) 7791 77922018-03-22T17:33:57.1010 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7793 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7794 7 ms, 2 read(s), 1 write(s), 7 fetch(es) 7795 77962018-03-22T17:33:57.1010 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7797 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7798 0 ms, 2 read(s), 17 fetch(es) 7799 78002018-03-22T17:33:57.1010 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7801 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7802 0 ms, 2 read(s), 75 fetch(es) 7803 78042018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7805 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7806 10 ms, 5 read(s), 305 fetch(es) 7807 78082018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7809 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7810 0 ms, 2 read(s), 25 fetch(es) 7811 78122018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7813 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7814 0 ms, 2 read(s), 7 fetch(es) 7815 78162018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7817 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7818 0 ms, 1 read(s), 165 fetch(es) 7819 78202018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7821 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7822 0 ms, 2 read(s), 31 fetch(es) 7823 78242018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7825 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7826 0 ms, 1 read(s), 141 fetch(es) 7827 78282018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7829 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7830 0 ms, 5 read(s), 29 fetch(es) 7831 78322018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7833 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7834 0 ms, 2 read(s), 69 fetch(es) 7835 78362018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7837 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7838 0 ms, 107 fetch(es) 7839 78402018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7841 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7842 0 ms, 2 read(s), 303 fetch(es) 7843 78442018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7845 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7846 0 ms, 2 read(s), 13 fetch(es) 7847 78482018-03-22T17:33:57.1120 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7849 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7850 0 ms, 5 fetch(es) 7851 78522018-03-22T17:33:57.1130 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7853 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7854 0 ms, 2 read(s), 31 fetch(es) 7855 78562018-03-22T17:33:57.1130 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7857 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7858 0 ms, 6 read(s), 285 fetch(es), 60 mark(s) 7859 78602018-03-22T17:33:57.1350 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7861 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7862 8 ms, 2 read(s), 1 write(s), 45 fetch(es) 7863 78642018-03-22T17:33:57.1350 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7865 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7866 0 ms, 3 read(s), 89 fetch(es) 7867 78682018-03-22T17:33:57.1350 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7869 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7870 0 ms, 3 read(s), 61 fetch(es), 12 mark(s) 7871 78722018-03-22T17:33:57.1420 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7873 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7874 7 ms, 2 read(s), 1 write(s), 59 fetch(es) 7875 78762018-03-22T17:33:57.1480 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7877 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7878 5 ms, 3 read(s), 1 write(s), 206 fetch(es), 48 mark(s) 7879 78802018-03-22T17:33:57.1510 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7881 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7882 2 ms, 2 read(s), 1 write(s), 101 fetch(es) 7883 78842018-03-22T17:33:57.1510 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7885 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7886 0 ms, 2 read(s), 33 fetch(es) 7887 78882018-03-22T17:33:57.1510 (12351:0x7f0174bdd978) SWEEP_PROGRESS 7889 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 7890 0 ms, 2 read(s), 69 fetch(es) 7891""" 7892 output = """AttachmentInfo(attachment_id=8, database='/opt/firebird/examples/empbuild/employee.fdb', charset='NONE', protocol='<internal>', address='<internal>', user='SYSDBA', role='NONE', remote_process=None, remote_pid=None) 7893EventSweepProgress(event_id=1, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 56, 982000), attachment_id=8, run_time=0, reads=None, writes=None, fetches=5, marks=None, access=None) 7894EventSweepProgress(event_id=2, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 56, 983000), attachment_id=8, run_time=0, reads=6, writes=None, fetches=409, marks=None, access=None) 7895EventSweepProgress(event_id=3, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 56, 992000), attachment_id=8, run_time=9, reads=5, writes=None, fetches=345, marks=39, access=None) 7896EventSweepProgress(event_id=4, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 56, 993000), attachment_id=8, run_time=0, reads=4, writes=None, fetches=251, marks=24, access=None) 7897EventSweepProgress(event_id=5, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57), attachment_id=8, run_time=7, reads=14, writes=None, fetches=877, marks=4, access=None) 7898EventSweepProgress(event_id=6, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57), attachment_id=8, run_time=0, reads=2, writes=None, fetches=115, marks=None, access=None) 7899EventSweepProgress(event_id=7, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57), attachment_id=8, run_time=0, reads=2, writes=None, fetches=7, marks=None, access=None) 7900EventSweepProgress(event_id=8, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 2000), attachment_id=8, run_time=1, reads=2, writes=None, fetches=25, marks=None, access=None) 7901EventSweepProgress(event_id=9, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 7000), attachment_id=8, run_time=5, reads=4, writes=1, fetches=339, marks=97, access=None) 7902EventSweepProgress(event_id=10, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 9000), attachment_id=8, run_time=2, reads=6, writes=1, fetches=467, marks=None, access=None) 7903EventSweepProgress(event_id=11, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 10000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=149, marks=None, access=None) 7904EventSweepProgress(event_id=12, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 93000), attachment_id=8, run_time=83, reads=11, writes=8, fetches=2307, marks=657, access=None) 7905EventSweepProgress(event_id=13, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 101000), attachment_id=8, run_time=7, reads=2, writes=1, fetches=7, marks=None, access=None) 7906EventSweepProgress(event_id=14, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 101000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=17, marks=None, access=None) 7907EventSweepProgress(event_id=15, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 101000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=75, marks=None, access=None) 7908EventSweepProgress(event_id=16, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=10, reads=5, writes=None, fetches=305, marks=None, access=None) 7909EventSweepProgress(event_id=17, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=25, marks=None, access=None) 7910EventSweepProgress(event_id=18, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=7, marks=None, access=None) 7911EventSweepProgress(event_id=19, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=0, reads=1, writes=None, fetches=165, marks=None, access=None) 7912EventSweepProgress(event_id=20, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=31, marks=None, access=None) 7913EventSweepProgress(event_id=21, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=0, reads=1, writes=None, fetches=141, marks=None, access=None) 7914EventSweepProgress(event_id=22, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=0, reads=5, writes=None, fetches=29, marks=None, access=None) 7915EventSweepProgress(event_id=23, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=69, marks=None, access=None) 7916EventSweepProgress(event_id=24, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=0, reads=None, writes=None, fetches=107, marks=None, access=None) 7917EventSweepProgress(event_id=25, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=303, marks=None, access=None) 7918EventSweepProgress(event_id=26, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=13, marks=None, access=None) 7919EventSweepProgress(event_id=27, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 112000), attachment_id=8, run_time=0, reads=None, writes=None, fetches=5, marks=None, access=None) 7920EventSweepProgress(event_id=28, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 113000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=31, marks=None, access=None) 7921EventSweepProgress(event_id=29, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 113000), attachment_id=8, run_time=0, reads=6, writes=None, fetches=285, marks=60, access=None) 7922EventSweepProgress(event_id=30, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 135000), attachment_id=8, run_time=8, reads=2, writes=1, fetches=45, marks=None, access=None) 7923EventSweepProgress(event_id=31, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 135000), attachment_id=8, run_time=0, reads=3, writes=None, fetches=89, marks=None, access=None) 7924EventSweepProgress(event_id=32, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 135000), attachment_id=8, run_time=0, reads=3, writes=None, fetches=61, marks=12, access=None) 7925EventSweepProgress(event_id=33, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 142000), attachment_id=8, run_time=7, reads=2, writes=1, fetches=59, marks=None, access=None) 7926EventSweepProgress(event_id=34, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 148000), attachment_id=8, run_time=5, reads=3, writes=1, fetches=206, marks=48, access=None) 7927EventSweepProgress(event_id=35, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 151000), attachment_id=8, run_time=2, reads=2, writes=1, fetches=101, marks=None, access=None) 7928EventSweepProgress(event_id=36, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 151000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=33, marks=None, access=None) 7929EventSweepProgress(event_id=37, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 151000), attachment_id=8, run_time=0, reads=2, writes=None, fetches=69, marks=None, access=None) 7930""" 7931 self._check_events(trace_lines, output) 7932 def test_sweep_progress_performance(self): 7933 trace_lines = """2018-03-29T15:23:01.3050 (7035:0x7fde644e4978) SWEEP_PROGRESS 7934 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 7935 2 ms, 1 read(s), 11 fetch(es), 2 mark(s) 7936 7937Table Natural Index Update Insert Delete Backout Purge Expunge 7938*************************************************************************************************************** 7939RDB$DATABASE 1 1 7940 79412018-03-29T15:23:01.3130 (7035:0x7fde644e4978) SWEEP_PROGRESS 7942 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 7943 7 ms, 8 read(s), 436 fetch(es), 9 mark(s) 7944 7945Table Natural Index Update Insert Delete Backout Purge Expunge 7946*************************************************************************************************************** 7947RDB$FIELDS 199 3 7948 79492018-03-29T15:23:01.3150 (7035:0x7fde644e4978) SWEEP_PROGRESS 7950 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 7951 1 ms, 4 read(s), 229 fetch(es) 7952 7953Table Natural Index Update Insert Delete Backout Purge Expunge 7954*************************************************************************************************************** 7955RDB$INDEX_SEGMENTS 111 7956 79572018-03-29T15:23:01.3150 (7035:0x7fde644e4978) SWEEP_PROGRESS 7958 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 7959 0 ms, 3 read(s), 179 fetch(es) 7960 7961Table Natural Index Update Insert Delete Backout Purge Expunge 7962*************************************************************************************************************** 7963RDB$INDICES 87 7964 79652018-03-29T15:23:01.3370 (7035:0x7fde644e4978) SWEEP_PROGRESS 7966 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 7967 21 ms, 18 read(s), 1 write(s), 927 fetch(es), 21 mark(s) 7968 7969Table Natural Index Update Insert Delete Backout Purge Expunge 7970*************************************************************************************************************** 7971RDB$RELATION_FIELDS 420 4 7972 79732018-03-29T15:23:01.3440 (7035:0x7fde644e4978) SWEEP_PROGRESS 7974 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 7975 7 ms, 2 read(s), 1 write(s), 143 fetch(es), 10 mark(s) 7976 7977Table Natural Index Update Insert Delete Backout Purge Expunge 7978*************************************************************************************************************** 7979RDB$RELATIONS 53 2 7980 79812018-03-29T15:23:01.3610 (7035:0x7fde644e4978) SWEEP_PROGRESS 7982 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 7983 17 ms, 2 read(s), 1 write(s), 7 fetch(es) 7984 7985Table Natural Index Update Insert Delete Backout Purge Expunge 7986*************************************************************************************************************** 7987RDB$VIEW_RELATIONS 2 7988 79892018-03-29T15:23:01.3610 (7035:0x7fde644e4978) SWEEP_PROGRESS 7990 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 7991 0 ms, 2 read(s), 25 fetch(es) 7992 7993Table Natural Index Update Insert Delete Backout Purge Expunge 7994*************************************************************************************************************** 7995RDB$FORMATS 11 7996 79972018-03-29T15:23:01.3860 (7035:0x7fde644e4978) SWEEP_PROGRESS 7998 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 7999 24 ms, 5 read(s), 1 write(s), 94 fetch(es), 4 mark(s) 8000 8001Table Natural Index Update Insert Delete Backout Purge Expunge 8002*************************************************************************************************************** 8003RDB$SECURITY_CLASSES 39 1 8004 80052018-03-29T15:23:01.3940 (7035:0x7fde644e4978) SWEEP_PROGRESS 8006 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8007 7 ms, 6 read(s), 467 fetch(es) 8008 8009Table Natural Index Update Insert Delete Backout Purge Expunge 8010*************************************************************************************************************** 8011RDB$TYPES 228 8012 80132018-03-29T15:23:01.3960 (7035:0x7fde644e4978) SWEEP_PROGRESS 8014 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8015 1 ms, 2 read(s), 149 fetch(es) 8016 8017Table Natural Index Update Insert Delete Backout Purge Expunge 8018*************************************************************************************************************** 8019RDB$TRIGGERS 67 8020 80212018-03-29T15:23:01.3980 (7035:0x7fde644e4978) SWEEP_PROGRESS 8022 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8023 1 ms, 8 read(s), 341 fetch(es) 8024 8025Table Natural Index Update Insert Delete Backout Purge Expunge 8026*************************************************************************************************************** 8027RDB$DEPENDENCIES 163 8028 80292018-03-29T15:23:01.3980 (7035:0x7fde644e4978) SWEEP_PROGRESS 8030 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8031 0 ms, 2 read(s), 7 fetch(es) 8032 8033Table Natural Index Update Insert Delete Backout Purge Expunge 8034*************************************************************************************************************** 8035RDB$FUNCTIONS 2 8036 80372018-03-29T15:23:01.3980 (7035:0x7fde644e4978) SWEEP_PROGRESS 8038 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8039 0 ms, 2 read(s), 17 fetch(es) 8040 8041Table Natural Index Update Insert Delete Backout Purge Expunge 8042*************************************************************************************************************** 8043RDB$FUNCTION_ARGUMENTS 7 8044 80452018-03-29T15:23:01.3980 (7035:0x7fde644e4978) SWEEP_PROGRESS 8046 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8047 0 ms, 2 read(s), 75 fetch(es) 8048 8049Table Natural Index Update Insert Delete Backout Purge Expunge 8050*************************************************************************************************************** 8051RDB$TRIGGER_MESSAGES 36 8052 80532018-03-29T15:23:01.3990 (7035:0x7fde644e4978) SWEEP_PROGRESS 8054 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8055 1 ms, 5 read(s), 305 fetch(es) 8056 8057Table Natural Index Update Insert Delete Backout Purge Expunge 8058*************************************************************************************************************** 8059RDB$USER_PRIVILEGES 148 8060 80612018-03-29T15:23:01.4230 (7035:0x7fde644e4978) SWEEP_PROGRESS 8062 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8063 0 ms, 2 read(s), 25 fetch(es) 8064 8065Table Natural Index Update Insert Delete Backout Purge Expunge 8066*************************************************************************************************************** 8067RDB$GENERATORS 11 8068 80692018-03-29T15:23:01.4230 (7035:0x7fde644e4978) SWEEP_PROGRESS 8070 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8071 0 ms, 2 read(s), 7 fetch(es) 8072 8073Table Natural Index Update Insert Delete Backout Purge Expunge 8074*************************************************************************************************************** 8075RDB$FIELD_DIMENSIONS 2 8076 80772018-03-29T15:23:01.4230 (7035:0x7fde644e4978) SWEEP_PROGRESS 8078 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8079 0 ms, 1 read(s), 165 fetch(es) 8080 8081Table Natural Index Update Insert Delete Backout Purge Expunge 8082*************************************************************************************************************** 8083RDB$RELATION_CONSTRAINTS 80 8084 80852018-03-29T15:23:01.4230 (7035:0x7fde644e4978) SWEEP_PROGRESS 8086 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8087 0 ms, 2 read(s), 31 fetch(es) 8088 8089Table Natural Index Update Insert Delete Backout Purge Expunge 8090*************************************************************************************************************** 8091RDB$REF_CONSTRAINTS 14 8092 80932018-03-29T15:23:01.4290 (7035:0x7fde644e4978) SWEEP_PROGRESS 8094 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8095 5 ms, 1 read(s), 141 fetch(es) 8096 8097Table Natural Index Update Insert Delete Backout Purge Expunge 8098*************************************************************************************************************** 8099RDB$CHECK_CONSTRAINTS 68 8100 81012018-03-29T15:23:01.4300 (7035:0x7fde644e4978) SWEEP_PROGRESS 8102 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8103 0 ms, 5 read(s), 29 fetch(es) 8104 8105Table Natural Index Update Insert Delete Backout Purge Expunge 8106*************************************************************************************************************** 8107RDB$PROCEDURES 10 8108 81092018-03-29T15:23:01.4300 (7035:0x7fde644e4978) SWEEP_PROGRESS 8110 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8111 0 ms, 2 read(s), 69 fetch(es) 8112 8113Table Natural Index Update Insert Delete Backout Purge Expunge 8114*************************************************************************************************************** 8115RDB$PROCEDURE_PARAMETERS 33 8116 81172018-03-29T15:23:01.4300 (7035:0x7fde644e4978) SWEEP_PROGRESS 8118 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8119 0 ms, 107 fetch(es) 8120 8121Table Natural Index Update Insert Delete Backout Purge Expunge 8122*************************************************************************************************************** 8123RDB$CHARACTER_SETS 52 8124 81252018-03-29T15:23:01.4300 (7035:0x7fde644e4978) SWEEP_PROGRESS 8126 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8127 0 ms, 2 read(s), 303 fetch(es) 8128 8129Table Natural Index Update Insert Delete Backout Purge Expunge 8130*************************************************************************************************************** 8131RDB$COLLATIONS 148 8132 81332018-03-29T15:23:01.4310 (7035:0x7fde644e4978) SWEEP_PROGRESS 8134 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8135 0 ms, 2 read(s), 13 fetch(es) 8136 8137Table Natural Index Update Insert Delete Backout Purge Expunge 8138*************************************************************************************************************** 8139RDB$EXCEPTIONS 5 8140 81412018-03-29T15:23:01.4310 (7035:0x7fde644e4978) SWEEP_PROGRESS 8142 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8143 0 ms, 5 fetch(es) 8144 8145Table Natural Index Update Insert Delete Backout Purge Expunge 8146*************************************************************************************************************** 8147RDB$ROLES 1 8148 81492018-03-29T15:23:01.4310 (7035:0x7fde644e4978) SWEEP_PROGRESS 8150 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8151 0 ms, 2 read(s), 31 fetch(es) 8152 8153Table Natural Index Update Insert Delete Backout Purge Expunge 8154*************************************************************************************************************** 8155COUNTRY 14 8156 81572018-03-29T15:23:01.4310 (7035:0x7fde644e4978) SWEEP_PROGRESS 8158 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8159 0 ms, 4 read(s), 69 fetch(es) 8160 8161Table Natural Index Update Insert Delete Backout Purge Expunge 8162*************************************************************************************************************** 8163JOB 31 8164 81652018-03-29T15:23:01.4310 (7035:0x7fde644e4978) SWEEP_PROGRESS 8166 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8167 0 ms, 2 read(s), 45 fetch(es) 8168 8169Table Natural Index Update Insert Delete Backout Purge Expunge 8170*************************************************************************************************************** 8171DEPARTMENT 21 8172 81732018-03-29T15:23:01.4310 (7035:0x7fde644e4978) SWEEP_PROGRESS 8174 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8175 0 ms, 3 read(s), 89 fetch(es) 8176 8177Table Natural Index Update Insert Delete Backout Purge Expunge 8178*************************************************************************************************************** 8179EMPLOYEE 42 8180 81812018-03-29T15:23:01.4310 (7035:0x7fde644e4978) SWEEP_PROGRESS 8182 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8183 0 ms, 2 read(s), 15 fetch(es) 8184 8185Table Natural Index Update Insert Delete Backout Purge Expunge 8186*************************************************************************************************************** 8187PROJECT 6 8188 81892018-03-29T15:23:01.4310 (7035:0x7fde644e4978) SWEEP_PROGRESS 8190 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8191 0 ms, 2 read(s), 59 fetch(es) 8192 8193Table Natural Index Update Insert Delete Backout Purge Expunge 8194*************************************************************************************************************** 8195EMPLOYEE_PROJECT 28 8196 81972018-03-29T15:23:01.4320 (7035:0x7fde644e4978) SWEEP_PROGRESS 8198 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8199 0 ms, 2 read(s), 51 fetch(es) 8200 8201Table Natural Index Update Insert Delete Backout Purge Expunge 8202*************************************************************************************************************** 8203PROJ_DEPT_BUDGET 24 8204 82052018-03-29T15:23:01.4320 (7035:0x7fde644e4978) SWEEP_PROGRESS 8206 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8207 0 ms, 2 read(s), 101 fetch(es) 8208 8209Table Natural Index Update Insert Delete Backout Purge Expunge 8210*************************************************************************************************************** 8211SALARY_HISTORY 49 8212 82132018-03-29T15:23:01.4320 (7035:0x7fde644e4978) SWEEP_PROGRESS 8214 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8215 0 ms, 2 read(s), 33 fetch(es) 8216 8217Table Natural Index Update Insert Delete Backout Purge Expunge 8218*************************************************************************************************************** 8219CUSTOMER 15 8220 82212018-03-29T15:23:01.4320 (7035:0x7fde644e4978) SWEEP_PROGRESS 8222 /opt/firebird/examples/empbuild/employee.fdb (ATT_24, SYSDBA:NONE, NONE, <internal>) 8223 0 ms, 2 read(s), 69 fetch(es) 8224 8225Table Natural Index Update Insert Delete Backout Purge Expunge 8226*************************************************************************************************************** 8227SALES 33 8228""" 8229 output = """AttachmentInfo(attachment_id=24, database='/opt/firebird/examples/empbuild/employee.fdb', charset='NONE', protocol='<internal>', address='<internal>', user='SYSDBA', role='NONE', remote_process=None, remote_pid=None) 8230EventSweepProgress(event_id=1, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 305000), attachment_id=24, run_time=2, reads=1, writes=None, fetches=11, marks=2, access=[AccessTuple(table='RDB$DATABASE', natural=1, index=0, update=0, insert=0, delete=0, backout=0, purge=1, expunge=0)]) 8231EventSweepProgress(event_id=2, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 313000), attachment_id=24, run_time=7, reads=8, writes=None, fetches=436, marks=9, access=[AccessTuple(table='RDB$FIELDS', natural=199, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=3)]) 8232EventSweepProgress(event_id=3, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 315000), attachment_id=24, run_time=1, reads=4, writes=None, fetches=229, marks=None, access=[AccessTuple(table='RDB$INDEX_SEGMENTS', natural=111, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8233EventSweepProgress(event_id=4, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 315000), attachment_id=24, run_time=0, reads=3, writes=None, fetches=179, marks=None, access=[AccessTuple(table='RDB$INDICES', natural=87, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8234EventSweepProgress(event_id=5, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 337000), attachment_id=24, run_time=21, reads=18, writes=1, fetches=927, marks=21, access=[AccessTuple(table='RDB$RELATION_FIELDS', natural=420, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=4)]) 8235EventSweepProgress(event_id=6, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 344000), attachment_id=24, run_time=7, reads=2, writes=1, fetches=143, marks=10, access=[AccessTuple(table='RDB$RELATIONS', natural=53, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=2)]) 8236EventSweepProgress(event_id=7, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 361000), attachment_id=24, run_time=17, reads=2, writes=1, fetches=7, marks=None, access=[AccessTuple(table='RDB$VIEW_RELATIONS', natural=2, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8237EventSweepProgress(event_id=8, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 361000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=25, marks=None, access=[AccessTuple(table='RDB$FORMATS', natural=11, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8238EventSweepProgress(event_id=9, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 386000), attachment_id=24, run_time=24, reads=5, writes=1, fetches=94, marks=4, access=[AccessTuple(table='RDB$SECURITY_CLASSES', natural=39, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=1)]) 8239EventSweepProgress(event_id=10, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 394000), attachment_id=24, run_time=7, reads=6, writes=None, fetches=467, marks=None, access=[AccessTuple(table='RDB$TYPES', natural=228, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8240EventSweepProgress(event_id=11, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 396000), attachment_id=24, run_time=1, reads=2, writes=None, fetches=149, marks=None, access=[AccessTuple(table='RDB$TRIGGERS', natural=67, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8241EventSweepProgress(event_id=12, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 398000), attachment_id=24, run_time=1, reads=8, writes=None, fetches=341, marks=None, access=[AccessTuple(table='RDB$DEPENDENCIES', natural=163, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8242EventSweepProgress(event_id=13, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 398000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=7, marks=None, access=[AccessTuple(table='RDB$FUNCTIONS', natural=2, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8243EventSweepProgress(event_id=14, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 398000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=17, marks=None, access=[AccessTuple(table='RDB$FUNCTION_ARGUMENTS', natural=7, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8244EventSweepProgress(event_id=15, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 398000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=75, marks=None, access=[AccessTuple(table='RDB$TRIGGER_MESSAGES', natural=36, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8245EventSweepProgress(event_id=16, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 399000), attachment_id=24, run_time=1, reads=5, writes=None, fetches=305, marks=None, access=[AccessTuple(table='RDB$USER_PRIVILEGES', natural=148, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8246EventSweepProgress(event_id=17, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 423000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=25, marks=None, access=[AccessTuple(table='RDB$GENERATORS', natural=11, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8247EventSweepProgress(event_id=18, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 423000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=7, marks=None, access=[AccessTuple(table='RDB$FIELD_DIMENSIONS', natural=2, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8248EventSweepProgress(event_id=19, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 423000), attachment_id=24, run_time=0, reads=1, writes=None, fetches=165, marks=None, access=[AccessTuple(table='RDB$RELATION_CONSTRAINTS', natural=80, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8249EventSweepProgress(event_id=20, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 423000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=31, marks=None, access=[AccessTuple(table='RDB$REF_CONSTRAINTS', natural=14, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8250EventSweepProgress(event_id=21, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 429000), attachment_id=24, run_time=5, reads=1, writes=None, fetches=141, marks=None, access=[AccessTuple(table='RDB$CHECK_CONSTRAINTS', natural=68, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8251EventSweepProgress(event_id=22, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 430000), attachment_id=24, run_time=0, reads=5, writes=None, fetches=29, marks=None, access=[AccessTuple(table='RDB$PROCEDURES', natural=10, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8252EventSweepProgress(event_id=23, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 430000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=69, marks=None, access=[AccessTuple(table='RDB$PROCEDURE_PARAMETERS', natural=33, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8253EventSweepProgress(event_id=24, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 430000), attachment_id=24, run_time=0, reads=None, writes=None, fetches=107, marks=None, access=[AccessTuple(table='RDB$CHARACTER_SETS', natural=52, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8254EventSweepProgress(event_id=25, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 430000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=303, marks=None, access=[AccessTuple(table='RDB$COLLATIONS', natural=148, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8255EventSweepProgress(event_id=26, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 431000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=13, marks=None, access=[AccessTuple(table='RDB$EXCEPTIONS', natural=5, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8256EventSweepProgress(event_id=27, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 431000), attachment_id=24, run_time=0, reads=None, writes=None, fetches=5, marks=None, access=[AccessTuple(table='RDB$ROLES', natural=1, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8257EventSweepProgress(event_id=28, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 431000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=31, marks=None, access=[AccessTuple(table='COUNTRY', natural=14, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8258EventSweepProgress(event_id=29, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 431000), attachment_id=24, run_time=0, reads=4, writes=None, fetches=69, marks=None, access=[AccessTuple(table='JOB', natural=31, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8259EventSweepProgress(event_id=30, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 431000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=45, marks=None, access=[AccessTuple(table='DEPARTMENT', natural=21, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8260EventSweepProgress(event_id=31, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 431000), attachment_id=24, run_time=0, reads=3, writes=None, fetches=89, marks=None, access=[AccessTuple(table='EMPLOYEE', natural=42, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8261EventSweepProgress(event_id=32, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 431000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=15, marks=None, access=[AccessTuple(table='PROJECT', natural=6, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8262EventSweepProgress(event_id=33, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 431000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=59, marks=None, access=[AccessTuple(table='EMPLOYEE_PROJECT', natural=28, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8263EventSweepProgress(event_id=34, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 432000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=51, marks=None, access=[AccessTuple(table='PROJ_DEPT_BUDGET', natural=24, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8264EventSweepProgress(event_id=35, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 432000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=101, marks=None, access=[AccessTuple(table='SALARY_HISTORY', natural=49, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8265EventSweepProgress(event_id=36, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 432000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=33, marks=None, access=[AccessTuple(table='CUSTOMER', natural=15, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8266EventSweepProgress(event_id=37, timestamp=datetime.datetime(2018, 3, 29, 15, 23, 1, 432000), attachment_id=24, run_time=0, reads=2, writes=None, fetches=69, marks=None, access=[AccessTuple(table='SALES', natural=33, index=0, update=0, insert=0, delete=0, backout=0, purge=0, expunge=0)]) 8267""" 8268 self._check_events(trace_lines, output) 8269 def test_sweep_finish(self): 8270 trace_lines = """2018-03-22T17:33:57.2270 (12351:0x7f0174bdd978) SWEEP_FINISH 8271 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 8272 8273Transaction counters: 8274 Oldest interesting 156 8275 Oldest active 156 8276 Oldest snapshot 156 8277 Next transaction 157 8278 257 ms, 177 read(s), 30 write(s), 8279 fetch(es), 945 mark(s) 8279 8280""" 8281 output = """AttachmentInfo(attachment_id=8, database='/opt/firebird/examples/empbuild/employee.fdb', charset='NONE', protocol='<internal>', address='<internal>', user='SYSDBA', role='NONE', remote_process=None, remote_pid=None) 8282EventSweepFinish(event_id=1, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 227000), attachment_id=8, oit=156, oat=156, ost=156, next=157, run_time=257, reads=177, writes=30, fetches=8279, marks=945) 8283""" 8284 self._check_events(trace_lines, output) 8285 def test_sweep_finish(self): 8286 trace_lines = """2018-03-22T17:33:57.2270 (12351:0x7f0174bdd978) SWEEP_FAILED 8287 /opt/firebird/examples/empbuild/employee.fdb (ATT_8, SYSDBA:NONE, NONE, <internal>) 8288""" 8289 output = """AttachmentInfo(attachment_id=8, database='/opt/firebird/examples/empbuild/employee.fdb', charset='NONE', protocol='<internal>', address='<internal>', user='SYSDBA', role='NONE', remote_process=None, remote_pid=None) 8290EventSweepFailed(event_id=1, timestamp=datetime.datetime(2018, 3, 22, 17, 33, 57, 227000), attachment_id=8) 8291""" 8292 self._check_events(trace_lines, output) 8293 def test_blr_compile(self): 8294 trace_lines = """2018-04-03T17:00:43.4270 (9772:0x7f2c5004b978) COMPILE_BLR 8295 /home/data/db/employee.fdb (ATT_5, SYSDBA:NONE, NONE, TCPv4:127.0.0.1) 8296 /bin/python:9737 8297------------------------------------------------------------------------------- 8298 0 blr_version5, 8299 1 blr_begin, 8300 2 blr_message, 0, 4,0, 8301 6 blr_varying2, 0,0, 15,0, 8302 11 blr_varying2, 0,0, 10,0, 8303 16 blr_short, 0, 8304 18 blr_short, 0, 8305 20 blr_loop, 8306 21 blr_receive, 0, 8307 23 blr_store, 8308 24 blr_relation, 7, 'C','O','U','N','T','R','Y', 0, 8309 34 blr_begin, 8310 35 blr_assignment, 8311 36 blr_parameter2, 0, 0,0, 2,0, 8312 42 blr_field, 0, 7, 'C','O','U','N','T','R','Y', 8313 52 blr_assignment, 8314 53 blr_parameter2, 0, 1,0, 3,0, 8315 59 blr_field, 0, 8, 'C','U','R','R','E','N','C','Y', 8316 70 blr_end, 8317 71 blr_end, 8318 72 blr_eoc 8319 8320 0 ms 8321 83222018-04-03T17:00:43.4270 (9772:0x7f2c5004b978) COMPILE_BLR 8323 /home/data/db/employee.fdb (ATT_5, SYSDBA:NONE, NONE, TCPv4:127.0.0.1) 8324 /bin/python:9737 8325------------------------------------------------------------------------------- 8326 0 blr_version5, 8327 1 blr_begin, 8328 2 blr_message, 0, 4,0, 8329 6 blr_varying2, 0,0, 15,0, 8330 11 blr_varying2, 0,0, 10,0, 8331 16 blr_short, 0 8332... 8333 0 ms 8334 83352018-04-03T17:00:43.4270 (9772:0x7f2c5004b978) COMPILE_BLR 8336 /home/data/db/employee.fdb (ATT_5, SYSDBA:NONE, NONE, TCPv4:127.0.0.1) 8337 /bin/python:9737 8338 8339Statement 22: 8340 0 ms 8341""" 8342 output = """AttachmentInfo(attachment_id=5, database='/home/data/db/employee.fdb', charset='NONE', protocol='TCPv4', address='127.0.0.1', user='SYSDBA', role='NONE', remote_process='/bin/python', remote_pid=9737) 8343EventBLRCompile(event_id=1, timestamp=datetime.datetime(2018, 4, 3, 17, 0, 43, 427000), status=' ', attachment_id=5, statement_id=None, content="0 blr_version5,\\n1 blr_begin,\\n2 blr_message, 0, 4,0,\\n6 blr_varying2, 0,0, 15,0,\\n11 blr_varying2, 0,0, 10,0,\\n16 blr_short, 0,\\n18 blr_short, 0,\\n20 blr_loop,\\n21 blr_receive, 0,\\n23 blr_store,\\n24 blr_relation, 7, 'C','O','U','N','T','R','Y', 0,\\n34 blr_begin,\\n35 blr_assignment,\\n36 blr_parameter2, 0, 0,0, 2,0,\\n42 blr_field, 0, 7, 'C','O','U','N','T','R','Y',\\n52 blr_assignment,\\n53 blr_parameter2, 0, 1,0, 3,0,\\n59 blr_field, 0, 8, 'C','U','R','R','E','N','C','Y',\\n70 blr_end,\\n71 blr_end,\\n72 blr_eoc", prepare_time=0) 8344EventBLRCompile(event_id=2, timestamp=datetime.datetime(2018, 4, 3, 17, 0, 43, 427000), status=' ', attachment_id=5, statement_id=None, content='0 blr_version5,\\n1 blr_begin,\\n2 blr_message, 0, 4,0,\\n6 blr_varying2, 0,0, 15,0,\\n11 blr_varying2, 0,0, 10,0,\\n16 blr_short, 0\\n...', prepare_time=0) 8345EventBLRCompile(event_id=3, timestamp=datetime.datetime(2018, 4, 3, 17, 0, 43, 427000), status=' ', attachment_id=5, statement_id=22, content=None, prepare_time=0) 8346""" 8347 self._check_events(trace_lines, output) 8348 def test_blr_execute(self): 8349 trace_lines = """2018-04-03T17:00:43.4280 (9772:0x7f2c5004b978) EXECUTE_BLR 8350 /home/data/db/employee.fdb (ATT_5, SYSDBA:NONE, NONE, TCPv4:127.0.0.1) 8351 /home/job/python/envs/pyfirebird/bin/python:9737 8352 (TRA_9, CONCURRENCY | NOWAIT | READ_WRITE) 8353------------------------------------------------------------------------------- 8354 0 blr_version5, 8355 1 blr_begin, 8356 2 blr_message, 0, 4,0, 8357 6 blr_varying2, 0,0, 15,0, 8358 11 blr_varying2, 0,0, 10,0, 8359 16 blr_short, 0, 8360 18 blr_short, 0, 8361 20 blr_loop, 8362 21 blr_receive, 0, 8363 23 blr_store, 8364 24 blr_relation, 7, 'C','O','U','N','T','R','Y', 0, 8365 34 blr_begin, 8366 35 blr_assignment, 8367 36 blr_parameter2, 0, 0,0, 2,0, 8368 42 blr_field, 0, 7, 'C','O','U','N','T','R','Y', 8369 52 blr_assignment, 8370 53 blr_parameter2, 0, 1,0, 3,0, 8371 59 blr_field, 0, 8, 'C','U','R','R','E','N','C','Y', 8372 70 blr_end, 8373 71 blr_end, 8374 72 blr_eoc 8375 8376 0 ms, 3 read(s), 7 fetch(es), 5 mark(s) 8377 8378Table Natural Index Update Insert Delete Backout Purge Expunge 8379*************************************************************************************************************** 8380COUNTRY 1 8381 83822018-04-03T17:00:43.4280 (9772:0x7f2c5004b978) EXECUTE_BLR 8383 /home/data/db/employee.fdb (ATT_5, SYSDBA:NONE, NONE, TCPv4:127.0.0.1) 8384 /home/job/python/envs/pyfirebird/bin/python:9737 8385 (TRA_9, CONCURRENCY | NOWAIT | READ_WRITE) 8386------------------------------------------------------------------------------- 8387 0 blr_version5, 8388 1 blr_begin, 8389 2 blr_message, 0, 4,0, 8390 6 blr_varying2, 0,0, 15,0, 8391 11 blr_varying2, 0,0, 10,0, 8392 16 blr_short, 0, 8393 18 blr_short, 0... 8394 0 ms, 3 read(s), 7 fetch(es), 5 mark(s) 8395 8396Table Natural Index Update Insert Delete Backout Purge Expunge 8397*************************************************************************************************************** 8398COUNTRY 1 8399 84002018-04-03T17:00:43.4280 (9772:0x7f2c5004b978) EXECUTE_BLR 8401 /home/data/db/employee.fdb (ATT_5, SYSDBA:NONE, NONE, TCPv4:127.0.0.1) 8402 /home/job/python/envs/pyfirebird/bin/python:9737 8403 (TRA_9, CONCURRENCY | NOWAIT | READ_WRITE) 8404Statement 22: 8405 0 ms, 3 read(s), 7 fetch(es), 5 mark(s) 8406""" 8407 output = """AttachmentInfo(attachment_id=5, database='/home/data/db/employee.fdb', charset='NONE', protocol='TCPv4', address='127.0.0.1', user='SYSDBA', role='NONE', remote_process='/home/job/python/envs/pyfirebird/bin/python', remote_pid=9737) 8408TransactionInfo(attachment_id=5, transaction_id=9, options=['CONCURRENCY', 'NOWAIT', 'READ_WRITE']) 8409EventBLRExecute(event_id=1, timestamp=datetime.datetime(2018, 4, 3, 17, 0, 43, 428000), status=' ', attachment_id=5, transaction_id=9, statement_id=None, content="0 blr_version5,\\n1 blr_begin,\\n2 blr_message, 0, 4,0,\\n6 blr_varying2, 0,0, 15,0,\\n11 blr_varying2, 0,0, 10,0,\\n16 blr_short, 0,\\n18 blr_short, 0,\\n20 blr_loop,\\n21 blr_receive, 0,\\n23 blr_store,\\n24 blr_relation, 7, 'C','O','U','N','T','R','Y', 0,\\n34 blr_begin,\\n35 blr_assignment,\\n36 blr_parameter2, 0, 0,0, 2,0,\\n42 blr_field, 0, 7, 'C','O','U','N','T','R','Y',\\n52 blr_assignment,\\n53 blr_parameter2, 0, 1,0, 3,0,\\n59 blr_field, 0, 8, 'C','U','R','R','E','N','C','Y',\\n70 blr_end,\\n71 blr_end,\\n72 blr_eoc", run_time=0, reads=3, writes=None, fetches=7, marks=5, access=[AccessTuple(table='COUNTRY', natural=0, index=0, update=0, insert=1, delete=0, backout=0, purge=0, expunge=0)]) 8410EventBLRExecute(event_id=2, timestamp=datetime.datetime(2018, 4, 3, 17, 0, 43, 428000), status=' ', attachment_id=5, transaction_id=9, statement_id=None, content='0 blr_version5,\\n1 blr_begin,\\n2 blr_message, 0, 4,0,\\n6 blr_varying2, 0,0, 15,0,\\n11 blr_varying2, 0,0, 10,0,\\n16 blr_short, 0,\\n18 blr_short, 0...', run_time=0, reads=3, writes=None, fetches=7, marks=5, access=[AccessTuple(table='COUNTRY', natural=0, index=0, update=0, insert=1, delete=0, backout=0, purge=0, expunge=0)]) 8411EventBLRExecute(event_id=3, timestamp=datetime.datetime(2018, 4, 3, 17, 0, 43, 428000), status=' ', attachment_id=5, transaction_id=9, statement_id=22, content=None, run_time=0, reads=3, writes=None, fetches=7, marks=5, access=None) 8412""" 8413 self._check_events(trace_lines, output) 8414 def test_dyn_execute(self): 8415 trace_lines = """2018-04-03T17:42:53.5590 (10474:0x7f0d8b4f0978) EXECUTE_DYN 8416 /opt/firebird/examples/empbuild/employee.fdb (ATT_40, SYSDBA:NONE, NONE, <internal>) 8417 (TRA_221, CONCURRENCY | WAIT | READ_WRITE) 8418------------------------------------------------------------------------------- 8419 0 gds__dyn_version_1, 8420 1 gds__dyn_delete_rel, 1,0, 'T', 8421 5 gds__dyn_end, 8422 0 gds__dyn_eoc 8423 20 ms 84242018-04-03T17:43:21.3650 (10474:0x7f0d8b4f0978) EXECUTE_DYN 8425 /opt/firebird/examples/empbuild/employee.fdb (ATT_40, SYSDBA:NONE, NONE, <internal>) 8426 (TRA_222, CONCURRENCY | WAIT | READ_WRITE) 8427------------------------------------------------------------------------------- 8428 0 gds__dyn_version_1, 8429 1 gds__dyn_begin, 8430 2 gds__dyn_def_local_fld, 31,0, 'C','O','U','N','T','R','Y',32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 8431 36 gds__dyn_fld_source, 31,0, 'C','O','U','N','T','R','Y','N','A','M','E',32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 8432 70 gds__dyn_rel_name, 1,0, 'T', 8433 74 gds__dyn_fld_position, 2,0, 0,0, 8434 79 gds__dyn_update_flag, 2,0, 1,0, 8435 84 gds__dyn_system_flag, 2,0, 0,0, 8436 89 gds__dyn_end, 8437 90 gds__dyn_def_sql_fld, 31,0, 'C','U','R','R','E','N','C','Y',32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, 8438 124 gds__dyn_fld_type, 2,0, 37,0, 8439 129 gds__dyn_fld_length, 2,0, 10,0, 8440 134 gds__dyn_fld_scale, 2,0, 0,0, 8441 139 gds__dyn_rel_name, 1,0, 'T', 8442 143 gds__dyn_fld_position, 2,0, 1,0, 8443 148 gds__dyn_update_flag, 2,0, 1,0, 8444 153 gds__dyn_system_flag, 2,0, 0,0, 8445 158 gds__dyn_end, 8446 159 gds__dyn_end, 8447 0 gds__dyn_eoc 8448 0 ms 84492018-03-29T13:28:45.8910 (5265:0x7f71ed580978) EXECUTE_DYN 8450 /opt/firebird/examples/empbuild/employee.fdb (ATT_20, SYSDBA:NONE, NONE, <internal>) 8451 (TRA_189, CONCURRENCY | WAIT | READ_WRITE) 8452 26 ms 8453""" 8454 output = """AttachmentInfo(attachment_id=40, database='/opt/firebird/examples/empbuild/employee.fdb', charset='NONE', protocol='<internal>', address='<internal>', user='SYSDBA', role='NONE', remote_process=None, remote_pid=None) 8455TransactionInfo(attachment_id=40, transaction_id=221, options=['CONCURRENCY', 'WAIT', 'READ_WRITE']) 8456EventDYNExecute(event_id=1, timestamp=datetime.datetime(2018, 4, 3, 17, 42, 53, 559000), status=' ', attachment_id=40, transaction_id=221, content="0 gds__dyn_version_1,\\n1 gds__dyn_delete_rel, 1,0, 'T',\\n5 gds__dyn_end,\\n0 gds__dyn_eoc", run_time=20) 8457TransactionInfo(attachment_id=40, transaction_id=222, options=['CONCURRENCY', 'WAIT', 'READ_WRITE']) 8458EventDYNExecute(event_id=2, timestamp=datetime.datetime(2018, 4, 3, 17, 43, 21, 365000), status=' ', attachment_id=40, transaction_id=222, content="0 gds__dyn_version_1,\\n1 gds__dyn_begin,\\n2 gds__dyn_def_local_fld, 31,0, 'C','O','U','N','T','R','Y',32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,\\n36 gds__dyn_fld_source, 31,0, 'C','O','U','N','T','R','Y','N','A','M','E',32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,\\n70 gds__dyn_rel_name, 1,0, 'T',\\n74 gds__dyn_fld_position, 2,0, 0,0,\\n79 gds__dyn_update_flag, 2,0, 1,0,\\n84 gds__dyn_system_flag, 2,0, 0,0,\\n89 gds__dyn_end,\\n90 gds__dyn_def_sql_fld, 31,0, 'C','U','R','R','E','N','C','Y',32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,\\n124 gds__dyn_fld_type, 2,0, 37,0,\\n129 gds__dyn_fld_length, 2,0, 10,0,\\n134 gds__dyn_fld_scale, 2,0, 0,0,\\n139 gds__dyn_rel_name, 1,0, 'T',\\n143 gds__dyn_fld_position, 2,0, 1,0,\\n148 gds__dyn_update_flag, 2,0, 1,0,\\n153 gds__dyn_system_flag, 2,0, 0,0,\\n158 gds__dyn_end,\\n159 gds__dyn_end,\\n0 gds__dyn_eoc", run_time=0) 8459AttachmentInfo(attachment_id=20, database='/opt/firebird/examples/empbuild/employee.fdb', charset='NONE', protocol='<internal>', address='<internal>', user='SYSDBA', role='NONE', remote_process=None, remote_pid=None) 8460TransactionInfo(attachment_id=20, transaction_id=189, options=['CONCURRENCY', 'WAIT', 'READ_WRITE']) 8461EventDYNExecute(event_id=3, timestamp=datetime.datetime(2018, 3, 29, 13, 28, 45, 891000), status=' ', attachment_id=20, transaction_id=189, content=None, run_time=26) 8462""" 8463 self._check_events(trace_lines, output) 8464 def test_unknown(self): 8465 # It could be an event unknown to trace plugin (case 1), or completelly new event unknown to trace parser (case 2) 8466 trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) Unknown event in ATTACH_DATABASE 8467 /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) 8468 /opt/firebird/bin/isql:8723 8469 84702018-03-22T10:06:59.5090 (4992:0x7f92a22a4978) EVENT_FROM_THE_FUTURE 8471This event may contain 8472various information 8473which could span 8474multiple lines. 8475 8476Yes, it could be very long! 8477""" 8478 output = """EventUnknown(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), data='Unknown event in ATTACH_DATABASE\\n/home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5)\\n/opt/firebird/bin/isql:8723') 8479EventUnknown(event_id=2, timestamp=datetime.datetime(2018, 3, 22, 10, 6, 59, 509000), data='EVENT_FROM_THE_FUTURE\\nThis event may contain\\nvarious information\\nwhich could span\\nmultiple lines.\\nYes, it could be very long!') 8480""" 8481 self._check_events(trace_lines, output) 8482 8483class TestUtils(FDBTestBase): 8484 def setUp(self): 8485 super(TestUtils, self).setUp() 8486 self.maxDiff = None 8487 def test_objectlist(self): 8488 Item = collections.namedtuple('Item', 'name,size,data') 8489 Point = collections.namedtuple('Point', 'x,y') 8490 data = [Item('A', 100, 'X' * 20), 8491 Item('Aaa', 95, 'X' * 50), 8492 Item('Abb', 90, 'Y' * 20), 8493 Item('B', 85, 'Y' * 50), 8494 Item('Baa', 80, 'Y' * 60), 8495 Item('Bab', 75, 'Z' * 20), 8496 Item('Bba', 65, 'Z' * 50), 8497 Item('Bbb', 70, 'Z' * 50), 8498 Item('C', 0, 'None'),] 8499 # 8500 olist = utils.ObjectList(data) 8501 # basic list operations 8502 self.assertEquals(len(data), len(olist)) 8503 self.assertListEqual(data, olist) 8504 self.assertListEqual(data, olist) 8505 self.assertEqual(olist[0], data[0]) 8506 self.assertEqual(olist.index(Item('B', 85, 'Y' * 50)), 3) 8507 del olist[3] 8508 self.assertEqual(len(olist), len(data) - 1) 8509 olist.insert(3, Item('B', 85, 'Y' * 50)) 8510 self.assertEquals(len(data), len(olist)) 8511 self.assertListEqual(data, olist) 8512 # sort - attrs 8513 olist.sort(['name'], reverse=True) 8514 self.assertListEqual(olist, [Item(name='C', size=0, data='None'), 8515 Item(name='Bbb', size=70, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8516 Item(name='Bba', size=65, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8517 Item(name='Bab', size=75, data='ZZZZZZZZZZZZZZZZZZZZ'), 8518 Item(name='Baa', size=80, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8519 Item(name='B', size=85, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8520 Item(name='Abb', size=90, data='YYYYYYYYYYYYYYYYYYYY'), 8521 Item(name='Aaa', size=95, data='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'), 8522 Item(name='A', size=100, data='XXXXXXXXXXXXXXXXXXXX')]) 8523 olist.sort(['data']) 8524 self.assertListEqual(olist, [Item(name='C', size=0, data='None'), 8525 Item(name='A', size=100, data='XXXXXXXXXXXXXXXXXXXX'), 8526 Item(name='Aaa', size=95, data='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'), 8527 Item(name='Abb', size=90, data='YYYYYYYYYYYYYYYYYYYY'), 8528 Item(name='B', size=85, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8529 Item(name='Baa', size=80, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8530 Item(name='Bab', size=75, data='ZZZZZZZZZZZZZZZZZZZZ'), 8531 Item(name='Bbb', size=70, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8532 Item(name='Bba', size=65, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ')]) 8533 olist.sort(['data', 'size']) 8534 self.assertListEqual(olist, [Item(name='C', size=0, data='None'), 8535 Item(name='A', size=100, data='XXXXXXXXXXXXXXXXXXXX'), 8536 Item(name='Aaa', size=95, data='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'), 8537 Item(name='Abb', size=90, data='YYYYYYYYYYYYYYYYYYYY'), 8538 Item(name='B', size=85, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8539 Item(name='Baa', size=80, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8540 Item(name='Bab', size=75, data='ZZZZZZZZZZZZZZZZZZZZ'), 8541 Item(name='Bba', size=65, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8542 Item(name='Bbb', size=70, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ')]) 8543 olist.sort(['name']) 8544 self.assertListEqual(data, olist) 8545 # sort - expr 8546 olist = utils.ObjectList(data) 8547 olist.sort(expr='item.size * len(item.name)', reverse=True) 8548 self.assertListEqual(olist, [Item(name='Aaa', size=95, data='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'), 8549 Item(name='Abb', size=90, data='YYYYYYYYYYYYYYYYYYYY'), 8550 Item(name='Baa', size=80, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8551 Item(name='Bab', size=75, data='ZZZZZZZZZZZZZZZZZZZZ'), 8552 Item(name='Bbb', size=70, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8553 Item(name='Bba', size=65, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8554 Item(name='A', size=100, data='XXXXXXXXXXXXXXXXXXXX'), 8555 Item(name='B', size=85, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8556 Item(name='C', size=0, data='None')]) 8557 olist.sort(expr=lambda x: x.size * len(x.name), reverse=True) 8558 self.assertListEqual(olist, [Item(name='Aaa', size=95, data='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'), 8559 Item(name='Abb', size=90, data='YYYYYYYYYYYYYYYYYYYY'), 8560 Item(name='Baa', size=80, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8561 Item(name='Bab', size=75, data='ZZZZZZZZZZZZZZZZZZZZ'), 8562 Item(name='Bbb', size=70, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8563 Item(name='Bba', size=65, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8564 Item(name='A', size=100, data='XXXXXXXXXXXXXXXXXXXX'), 8565 Item(name='B', size=85, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8566 Item(name='C', size=0, data='None')]) 8567 # filter/ifilter 8568 olist = utils.ObjectList(data) 8569 fc = olist.filter('item.name.startswith("B")') 8570 self.assertIsInstance(fc, utils.ObjectList) 8571 self.assertListEqual(fc, [Item(name='B', size=85, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8572 Item(name='Baa', size=80, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8573 Item(name='Bab', size=75, data='ZZZZZZZZZZZZZZZZZZZZ'), 8574 Item(name='Bba', size=65, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8575 Item(name='Bbb', size=70, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ')]) 8576 fc = olist.filter(lambda x: x.name.startswith("B")) 8577 self.assertListEqual(fc, [Item(name='B', size=85, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8578 Item(name='Baa', size=80, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8579 Item(name='Bab', size=75, data='ZZZZZZZZZZZZZZZZZZZZ'), 8580 Item(name='Bba', size=65, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8581 Item(name='Bbb', size=70, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ')]) 8582 self.assertListEqual(list(olist.ifilter('item.name.startswith("B")')), 8583 [Item(name='B', size=85, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8584 Item(name='Baa', size=80, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8585 Item(name='Bab', size=75, data='ZZZZZZZZZZZZZZZZZZZZ'), 8586 Item(name='Bba', size=65, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8587 Item(name='Bbb', size=70, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ')]) 8588 self.assertListEqual(list(olist.ifilter(lambda x: x.name.startswith("B"))), 8589 [Item(name='B', size=85, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8590 Item(name='Baa', size=80, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8591 Item(name='Bab', size=75, data='ZZZZZZZZZZZZZZZZZZZZ'), 8592 Item(name='Bba', size=65, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8593 Item(name='Bbb', size=70, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ')]) 8594 # report/ireport 8595 self.assertListEqual(olist.report('item.name', 'item.size'), 8596 [('A', 100), ('Aaa', 95), ('Abb', 90), ('B', 85), 8597 ('Baa', 80), ('Bab', 75), ('Bba', 65), ('Bbb', 70), ('C', 0)]) 8598 self.assertListEqual(olist.report(lambda x: (x.name, x.size)), 8599 [('A', 100), ('Aaa', 95), ('Abb', 90), ('B', 85), 8600 ('Baa', 80), ('Bab', 75), ('Bba', 65), ('Bbb', 70), ('C', 0)]) 8601 self.assertListEqual(list(olist.ireport('item.name', 'item.size')), 8602 [('A', 100), ('Aaa', 95), ('Abb', 90), ('B', 85), 8603 ('Baa', 80), ('Bab', 75), ('Bba', 65), ('Bbb', 70), ('C', 0)]) 8604 self.assertListEqual(olist.report('"name: %s, size: %d" % (item.name, item.size)'), 8605 ['name: A, size: 100', 'name: Aaa, size: 95', 'name: Abb, size: 90', 8606 'name: B, size: 85', 'name: Baa, size: 80', 'name: Bab, size: 75', 8607 'name: Bba, size: 65', 'name: Bbb, size: 70', 'name: C, size: 0']) 8608 self.assertListEqual(olist.report(lambda x: "name: %s, size: %d" % (x.name, x.size)), 8609 ['name: A, size: 100', 'name: Aaa, size: 95', 'name: Abb, size: 90', 8610 'name: B, size: 85', 'name: Baa, size: 80', 'name: Bab, size: 75', 8611 'name: Bba, size: 65', 'name: Bbb, size: 70', 'name: C, size: 0']) 8612 # ecount 8613 self.assertEqual(olist.ecount('item.name.startswith("B")'), 5) 8614 self.assertEqual(olist.ecount(lambda x: x.name.startswith("B")), 5) 8615 # split 8616 truelist, falselist = olist.split('item.name.startswith("B")') 8617 self.assertIsInstance(truelist, utils.ObjectList) 8618 self.assertIsInstance(falselist, utils.ObjectList) 8619 self.assertListEqual(list(truelist), [Item(name='B', size=85, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8620 Item(name='Baa', size=80, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8621 Item(name='Bab', size=75, data='ZZZZZZZZZZZZZZZZZZZZ'), 8622 Item(name='Bba', size=65, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8623 Item(name='Bbb', size=70, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ')]) 8624 self.assertListEqual(list(falselist), [Item('A', 100, 'X' * 20), Item('Aaa', 95, 'X' * 50), Item('Abb', 90, 'Y' * 20), 8625 Item(name='C', size=0, data='None')]) 8626 # extract 8627 truelist = olist.extract('item.name.startswith("A")') 8628 self.assertIsInstance(truelist, utils.ObjectList) 8629 self.assertListEqual(list(truelist), [Item('A', 100, 'X' * 20), Item('Aaa', 95, 'X' * 50), Item('Abb', 90, 'Y' * 20)]) 8630 self.assertListEqual(olist, [Item(name='B', size=85, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8631 Item(name='Baa', size=80, data='YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'), 8632 Item(name='Bab', size=75, data='ZZZZZZZZZZZZZZZZZZZZ'), 8633 Item(name='Bba', size=65, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8634 Item(name='Bbb', size=70, data='ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), 8635 Item(name='C', size=0, data='None')]) 8636 # clear 8637 olist.clear() 8638 self.assertEqual(len(olist), 0, 'list is not empty') 8639 # get 8640 olist.extend(data) 8641 with self.assertRaises(TypeError) as cm: 8642 item = olist.get('Baa') 8643 exc = cm.exception 8644 self.assertEqual(exc.args[0], "Key expression required") 8645 self.assertIs(olist.get('Baa', 'item.name'), olist[4]) 8646 olist = utils.ObjectList(data, Item, 'item.name') 8647 self.assertIs(olist.get('Baa'), olist[4]) 8648 self.assertIs(olist.get(80, 'item.size'), olist[4]) 8649 self.assertIs(olist.get(80, lambda x, value: x.size == value), olist[4]) 8650 olist.freeze() # Frozen list uses O(1) access via dict! 8651 self.assertIs(olist.get('Baa'), olist[4]) 8652 # contains 8653 self.assertTrue(olist.contains('Baa')) 8654 self.assertFalse(olist.contains('FX')) 8655 self.assertTrue(olist.contains('Baa', 'item.name')) 8656 self.assertTrue(olist.contains(80, 'item.size')) 8657 self.assertTrue(olist.contains(80, lambda x, value: x.size == value)) 8658 # immutability 8659 olist = utils.ObjectList(data) 8660 self.assertFalse(olist.frozen, "list is frozen") 8661 self.assertListEqual(olist, data) 8662 olist.freeze() 8663 self.assertTrue(olist.frozen, "list is not frozen") 8664 with self.assertRaises(TypeError) as cm: 8665 olist[0] = Point(1, 1) 8666 exc = cm.exception 8667 self.assertEqual(exc.args[0], "list is frozen") 8668 with self.assertRaises(TypeError) as cm: 8669 olist[0:2] = [Point(1, 1)] 8670 exc = cm.exception 8671 self.assertEqual(exc.args[0], "list is frozen") 8672 with self.assertRaises(TypeError) as cm: 8673 olist.append(Point(1, 1)) 8674 exc = cm.exception 8675 self.assertEqual(exc.args[0], "list is frozen") 8676 with self.assertRaises(TypeError) as cm: 8677 olist.insert(0, [Point(1, 1)]) 8678 exc = cm.exception 8679 self.assertEqual(exc.args[0], "list is frozen") 8680 with self.assertRaises(TypeError) as cm: 8681 olist.extend([Point(1, 1)]) 8682 exc = cm.exception 8683 self.assertEqual(exc.args[0], "list is frozen") 8684 with self.assertRaises(TypeError) as cm: 8685 olist.clear() 8686 exc = cm.exception 8687 self.assertEqual(exc.args[0], "list is frozen") 8688 with self.assertRaises(TypeError) as cm: 8689 olist.extract('True') 8690 exc = cm.exception 8691 self.assertEqual(exc.args[0], "list is frozen") 8692 with self.assertRaises(TypeError) as cm: 8693 del olist[0] 8694 exc = cm.exception 8695 self.assertEqual(exc.args[0], "list is frozen") 8696 with self.assertRaises(TypeError) as cm: 8697 del olist[0:2] 8698 exc = cm.exception 8699 self.assertEqual(exc.args[0], "list is frozen") 8700 # Limit to class(es) 8701 olist = utils.ObjectList(data, Item) 8702 olist = utils.ObjectList(_cls=(Item, Point)) 8703 olist.append(Point(1, 1)) 8704 olist.insert(0, Item('A', 10, 'XXX')) 8705 olist[1] = Point(2, 2) 8706 self.assertListEqual(olist, [Item('A', 10, 'XXX'), Point(2, 2)]) 8707 with self.assertRaises(TypeError) as cm: 8708 olist.append(list()) 8709 exc = cm.exception 8710 self.assertEqual(exc.args[0], "Value is not an instance of allowed class") 8711 # Key 8712 olist = utils.ObjectList(data, Item, 'item.name') 8713 self.assertEqual(olist.get('A'), Item('A', 100, 'X' * 20)) 8714 # any/all 8715 self.assertFalse(olist.all('item.size > 0')) 8716 self.assertTrue(olist.all('item.size < 200')) 8717 self.assertTrue(olist.any('item.size > 0')) 8718 self.assertTrue(olist.any('item.size < 200')) 8719 self.assertFalse(olist.any('item.size > 300')) 8720 8721class TestGstatParse(FDBTestBase): 8722 def setUp(self): 8723 super(TestGstatParse, self).setUp() 8724 def _parse_file(self, filename): 8725 with open(filename) as f: 8726 return gstat.parse(f) 8727 def test_locale(self): 8728 locale = getlocale(LC_ALL) 8729 if locale[0] is None: 8730 setlocale(LC_ALL,'') 8731 locale = getlocale(LC_ALL) 8732 try: 8733 db = self._parse_file(os.path.join(self.dbpath, 'gstat25-h.out')) 8734 self.assertEquals(locale, getlocale(LC_ALL), "Locale must not change") 8735 if sys.platform == 'win32': 8736 setlocale(LC_ALL, 'Czech_Czech Republic') 8737 else: 8738 setlocale(LC_ALL, 'cs_CZ') 8739 nlocale = getlocale(LC_ALL) 8740 db = self._parse_file(os.path.join(self.dbpath, 'gstat25-h.out')) 8741 self.assertEquals(nlocale, getlocale(LC_ALL), "Locale must not change") 8742 finally: 8743 pass 8744 #setlocale(LC_ALL, locale) 8745 def test_parse25_h(self): 8746 db = self._parse_file(os.path.join(self.dbpath, 'gstat25-h.out')) 8747 data = {'attributes': (0,), 'backup_diff_file': None, 'backup_guid': None, 'bumped_transaction': 1, 8748 'checksum': 12345, 'completed': None, 'continuation_file': None, 'continuation_files': 0, 8749 'creation_date': datetime.datetime(2013, 5, 27, 23, 40, 53), 'database_dialect': 3, 8750 'encrypted_blob_pages': None, 'encrypted_data_pages': None, 'encrypted_index_pages': None, 8751 'executed': datetime.datetime(2018, 4, 4, 15, 29, 10), 'filename': '/home/fdb/test/fbtest25.fdb', 8752 'flags': 0, 'generation': 2844, 'gstat_version': 2, 'implementation': None, 'implementation_id': 24, 8753 'indices': 0, 'last_logical_page': None, 'next_attachment_id': 1067, 'next_header_page': 0, 'next_transaction': 1807, 8754 'oat': 1807, 'ods_version': '11.2', 'oit': 204, 'ost': 1807, 'page_buffers': 0, 'page_size': 4096, 8755 'replay_logging_file': None, 'root_filename': None, 'sequence_number': 0, 'shadow_count': 0, 'sweep_interval': 20000, 8756 'system_change_number': None, 'tables': 0} 8757 self.assertIsInstance(db, gstat.StatDatabase) 8758 self.assertDictEqual(data, get_object_data(db), 'Unexpected output from parser (database hdr)') 8759 # 8760 self.assertFalse(db.has_table_stats()) 8761 self.assertFalse(db.has_index_stats()) 8762 self.assertFalse(db.has_row_stats()) 8763 self.assertFalse(db.has_encryption_stats()) 8764 self.assertFalse(db.has_system()) 8765 def test_parse25_a(self): 8766 db = self._parse_file(os.path.join(self.dbpath, 'gstat25-a.out')) 8767 # Database 8768 data = {'attributes': (0,), 'backup_diff_file': None, 'backup_guid': None, 'bumped_transaction': 1, 8769 'checksum': 12345, 'completed': None, 'continuation_file': None, 'continuation_files': 0, 8770 'creation_date': datetime.datetime(2013, 5, 27, 23, 40, 53), 'database_dialect': 3, 8771 'encrypted_blob_pages': None, 'encrypted_data_pages': None, 'encrypted_index_pages': None, 8772 'executed': datetime.datetime(2018, 4, 4, 15, 30, 10), 'filename': '/home/fdb/test/fbtest25.fdb', 8773 'flags': 0, 'generation': 2844, 'gstat_version': 2, 'implementation': None, 'implementation_id': 24, 8774 'indices': 39, 'last_logical_page': None, 'next_attachment_id': 1067, 'next_header_page': 0, 'next_transaction': 1807, 8775 'oat': 1807, 'ods_version': '11.2', 'oit': 204, 'ost': 1807, 'page_buffers': 0, 'page_size': 4096, 8776 'replay_logging_file': None, 'root_filename': None, 'sequence_number': 0, 'shadow_count': 0, 'sweep_interval': 20000, 8777 'system_change_number': None, 'tables': 15} 8778 self.assertDictEqual(data, get_object_data(db), 'Unexpected output from parser (database hdr)') 8779 # 8780 self.assertTrue(db.has_table_stats()) 8781 self.assertTrue(db.has_index_stats()) 8782 self.assertFalse(db.has_row_stats()) 8783 self.assertFalse(db.has_encryption_stats()) 8784 self.assertFalse(db.has_system()) 8785 # Tables 8786 data = [{'avg_fill': 86, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8787 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=1), 'index_root_page': 210, 'indices': 0, 8788 'max_versions': None, 'name': 'AR', 'primary_pointer_page': 209, 'table_id': 142, 'total_records': None, 8789 'total_versions': None}, 8790 {'avg_fill': 15, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8791 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 181, 'indices': 1, 8792 'max_versions': None, 'name': 'COUNTRY', 'primary_pointer_page': 180, 'table_id': 128, 'total_records': None, 8793 'total_versions': None}, 8794 {'avg_fill': 53, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8795 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 189, 'indices': 4, 8796 'max_versions': None, 'name': 'CUSTOMER', 'primary_pointer_page': 188, 'table_id': 132, 'total_records': None, 8797 'total_versions': None}, 8798 {'avg_fill': 47, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8799 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 185, 'indices': 5, 8800 'max_versions': None, 'name': 'DEPARTMENT', 'primary_pointer_page': 184, 'table_id': 130, 'total_records': None, 8801 'total_versions': None}, 8802 {'avg_fill': 44, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 2, 'data_pages': 2, 8803 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 187, 'indices': 4, 8804 'max_versions': None, 'name': 'EMPLOYEE', 'primary_pointer_page': 186, 'table_id': 131, 'total_records': None, 8805 'total_versions': None}, 8806 {'avg_fill': 20, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8807 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 196, 'indices': 3, 8808 'max_versions': None, 'name': 'EMPLOYEE_PROJECT', 'primary_pointer_page': 195, 'table_id': 135, 'total_records': None, 8809 'total_versions': None}, 8810 {'avg_fill': 73, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 3, 'data_pages': 3, 8811 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=2), 'index_root_page': 183, 'indices': 4, 8812 'max_versions': None, 'name': 'JOB', 'primary_pointer_page': 182, 'table_id': 129, 'total_records': None, 8813 'total_versions': None}, 8814 {'avg_fill': 29, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8815 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_root_page': 194, 'indices': 4, 8816 'max_versions': None, 'name': 'PROJECT', 'primary_pointer_page': 193, 'table_id': 134, 'total_records': None, 8817 'total_versions': None}, 8818 {'avg_fill': 80, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8819 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=1), 'index_root_page': 198, 'indices': 3, 8820 'max_versions': None, 'name': 'PROJ_DEPT_BUDGET', 'primary_pointer_page': 197, 'table_id': 136, 'total_records': None, 8821 'total_versions': None}, 8822 {'avg_fill': 58, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8823 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 200, 'indices': 4, 8824 'max_versions': None, 'name': 'SALARY_HISTORY', 'primary_pointer_page': 199, 'table_id': 137, 'total_records': None, 8825 'total_versions': None}, 8826 {'avg_fill': 68, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8827 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 202, 'indices': 6, 8828 'max_versions': None, 'name': 'SALES', 'primary_pointer_page': 201, 'table_id': 138, 'total_records': None, 8829 'total_versions': None}, 8830 {'avg_fill': 0, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 0, 'data_pages': 0, 8831 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 282, 'indices': 1, 8832 'max_versions': None, 'name': 'T', 'primary_pointer_page': 205, 'table_id': 235, 'total_records': None, 8833 'total_versions': None}, 8834 {'avg_fill': 20, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8835 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 208, 'indices': 0, 8836 'max_versions': None, 'name': 'T2', 'primary_pointer_page': 207, 'table_id': 141, 'total_records': None, 8837 'total_versions': None}, 8838 {'avg_fill': 0, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 0, 'data_pages': 0, 8839 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 204, 'indices': 0, 8840 'max_versions': None, 'name': 'T3', 'primary_pointer_page': 203, 'table_id': 139, 'total_records': None, 8841 'total_versions': None}, 8842 {'avg_fill': 4, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8843 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 192, 'indices': 0, 8844 'max_versions': None, 'name': 'T4', 'primary_pointer_page': 191, 'table_id': 133, 'total_records': None, 8845 'total_versions': None}] 8846 i = 0 8847 while i < len(db.tables): 8848 self.assertDictEqual(data[i], get_object_data(db.tables[i]), 'Unexpected output from parser (tables)') 8849 i += 1 8850 # Indices 8851 data = [{'avg_data_length': 6.5, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 8852 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY1', 'nodes': 14, 'total_dup': 0}, 8853 {'avg_data_length': 15.87, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 8854 'leaf_buckets': 1, 'max_dup': 0, 'name': 'CUSTNAMEX', 'nodes': 15, 'total_dup': 0}, 8855 {'avg_data_length': 17.27, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 8856 'leaf_buckets': 1, 'max_dup': 0, 'name': 'CUSTREGION', 'nodes': 15, 'total_dup': 0}, 8857 {'avg_data_length': 4.87, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 8858 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN23', 'nodes': 15, 'total_dup': 4}, 8859 {'avg_data_length': 1.13, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 8860 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY22', 'nodes': 15, 'total_dup': 0}, 8861 {'avg_data_length': 5.38, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 8862 'leaf_buckets': 1, 'max_dup': 3, 'name': 'BUDGETX', 'nodes': 21, 'total_dup': 7}, 8863 {'avg_data_length': 13.95, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 8864 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$4', 'nodes': 21, 'total_dup': 0}, 8865 {'avg_data_length': 1.14, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 8866 'leaf_buckets': 1, 'max_dup': 3, 'name': 'RDB$FOREIGN10', 'nodes': 21, 'total_dup': 3}, 8867 {'avg_data_length': 0.81, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 8868 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN6', 'nodes': 21, 'total_dup': 13}, 8869 {'avg_data_length': 1.71, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 8870 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY5', 'nodes': 21, 'total_dup': 0}, 8871 {'avg_data_length': 15.52, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_id': 1, 8872 'leaf_buckets': 1, 'max_dup': 0, 'name': 'NAMEX', 'nodes': 42, 'total_dup': 0}, 8873 {'avg_data_length': 0.81, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 8874 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN8', 'nodes': 42, 'total_dup': 23}, 8875 {'avg_data_length': 6.79, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 8876 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN9', 'nodes': 42, 'total_dup': 15}, 8877 {'avg_data_length': 1.31, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 8878 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY7', 'nodes': 42, 'total_dup': 0}, 8879 {'avg_data_length': 1.04, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 8880 'leaf_buckets': 1, 'max_dup': 2, 'name': 'RDB$FOREIGN15', 'nodes': 28, 'total_dup': 6}, 8881 {'avg_data_length': 0.86, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 8882 'leaf_buckets': 1, 'max_dup': 9, 'name': 'RDB$FOREIGN16', 'nodes': 28, 'total_dup': 23}, 8883 {'avg_data_length': 9.11, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 8884 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY14', 'nodes': 28, 'total_dup': 0}, 8885 {'avg_data_length': 10.9, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 8886 'leaf_buckets': 1, 'max_dup': 1, 'name': 'MAXSALX', 'nodes': 31, 'total_dup': 5}, 8887 {'avg_data_length': 10.29, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 8888 'leaf_buckets': 1, 'max_dup': 2, 'name': 'MINSALX', 'nodes': 31, 'total_dup': 7}, 8889 {'avg_data_length': 1.39, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 8890 'leaf_buckets': 1, 'max_dup': 20, 'name': 'RDB$FOREIGN3', 'nodes': 31, 'total_dup': 24}, 8891 {'avg_data_length': 10.45, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 8892 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY2', 'nodes': 31, 'total_dup': 0}, 8893 {'avg_data_length': 22.5, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 8894 'leaf_buckets': 1, 'max_dup': 0, 'name': 'PRODTYPEX', 'nodes': 6, 'total_dup': 0}, 8895 {'avg_data_length': 13.33, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 8896 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$11', 'nodes': 6, 'total_dup': 0}, 8897 {'avg_data_length': 1.33, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 8898 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$FOREIGN13', 'nodes': 6, 'total_dup': 0}, 8899 {'avg_data_length': 4.83, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 8900 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY12', 'nodes': 6, 'total_dup': 0}, 8901 {'avg_data_length': 0.71, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 8902 'leaf_buckets': 1, 'max_dup': 5, 'name': 'RDB$FOREIGN18', 'nodes': 24, 'total_dup': 15}, 8903 {'avg_data_length': 1.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 8904 'leaf_buckets': 1, 'max_dup': 8, 'name': 'RDB$FOREIGN19', 'nodes': 24, 'total_dup': 19}, 8905 {'avg_data_length': 6.83, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 8906 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY17', 'nodes': 24, 'total_dup': 0}, 8907 {'avg_data_length': 0.31, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 8908 'leaf_buckets': 1, 'max_dup': 21, 'name': 'CHANGEX', 'nodes': 49, 'total_dup': 46}, 8909 {'avg_data_length': 0.9, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 8910 'leaf_buckets': 1, 'max_dup': 2, 'name': 'RDB$FOREIGN21', 'nodes': 49, 'total_dup': 16}, 8911 {'avg_data_length': 18.29, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_id': 0, 8912 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY20', 'nodes': 49, 'total_dup': 0}, 8913 {'avg_data_length': 0.29, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 8914 'leaf_buckets': 1, 'max_dup': 28, 'name': 'UPDATERX', 'nodes': 49, 'total_dup': 46}, 8915 {'avg_data_length': 2.55, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 8916 'leaf_buckets': 1, 'max_dup': 6, 'name': 'NEEDX', 'nodes': 33, 'total_dup': 11}, 8917 {'avg_data_length': 1.85, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 8918 'leaf_buckets': 1, 'max_dup': 3, 'name': 'QTYX', 'nodes': 33, 'total_dup': 11}, 8919 {'avg_data_length': 0.52, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 8920 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN25', 'nodes': 33, 'total_dup': 18}, 8921 {'avg_data_length': 0.45, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 5, 8922 'leaf_buckets': 1, 'max_dup': 7, 'name': 'RDB$FOREIGN26', 'nodes': 33, 'total_dup': 25}, 8923 {'avg_data_length': 4.48, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 8924 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY24', 'nodes': 33, 'total_dup': 0}, 8925 {'avg_data_length': 0.97, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 8926 'leaf_buckets': 1, 'max_dup': 14, 'name': 'SALESTATX', 'nodes': 33, 'total_dup': 27}, 8927 {'avg_data_length': 0.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 8928 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY104', 'nodes': 0, 'total_dup': 0}] 8929 i = 0 8930 while i < len(db.tables): 8931 self.assertDictEqual(data[i], get_object_data(db.indices[i], ['table']), 'Unexpected output from parser (indices)') 8932 i += 1 8933 def test_parse25_d(self): 8934 db = self._parse_file(os.path.join(self.dbpath, 'gstat25-d.out')) 8935 # Database 8936 data = {'attributes': (0,), 'backup_diff_file': None, 'backup_guid': None, 'bumped_transaction': 1, 8937 'checksum': 12345, 'completed': None, 'continuation_file': None, 'continuation_files': 0, 8938 'creation_date': datetime.datetime(2013, 5, 27, 23, 40, 53), 'database_dialect': 3, 8939 'encrypted_blob_pages': None, 'encrypted_data_pages': None, 'encrypted_index_pages': None, 8940 'executed': datetime.datetime(2018, 4, 4, 15, 32, 25), 'filename': '/home/fdb/test/fbtest25.fdb', 8941 'flags': 0, 'generation': 2856, 'gstat_version': 2, 'implementation': None, 'implementation_id': 24, 8942 'indices': 0, 'last_logical_page': None, 'next_attachment_id': 1071, 'next_header_page': 0, 'next_transaction': 1811, 8943 'oat': 1811, 'ods_version': '11.2', 'oit': 204, 'ost': 1811, 'page_buffers': 0, 'page_size': 4096, 8944 'replay_logging_file': None, 'root_filename': None, 'sequence_number': 0, 'shadow_count': 0, 'sweep_interval': 20000, 8945 'system_change_number': None, 'tables': 15} 8946 self.assertDictEqual(data, get_object_data(db), 'Unexpected output from parser (database hdr)') 8947 # 8948 self.assertTrue(db.has_table_stats()) 8949 self.assertFalse(db.has_index_stats()) 8950 self.assertFalse(db.has_row_stats()) 8951 self.assertFalse(db.has_encryption_stats()) 8952 self.assertFalse(db.has_system()) 8953 # Tables 8954 data = [{'avg_fill': 86, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8955 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=1), 'index_root_page': 210, 'indices': 0, 8956 'max_versions': None, 'name': 'AR', 'primary_pointer_page': 209, 'table_id': 142, 'total_records': None, 8957 'total_versions': None}, 8958 {'avg_fill': 15, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8959 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 181, 'indices': 0, 8960 'max_versions': None, 'name': 'COUNTRY', 'primary_pointer_page': 180, 'table_id': 128, 'total_records': None, 8961 'total_versions': None}, 8962 {'avg_fill': 53, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8963 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 189, 'indices': 0, 8964 'max_versions': None, 'name': 'CUSTOMER', 'primary_pointer_page': 188, 'table_id': 132, 'total_records': None, 8965 'total_versions': None}, 8966 {'avg_fill': 47, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8967 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 185, 'indices': 0, 8968 'max_versions': None, 'name': 'DEPARTMENT', 'primary_pointer_page': 184, 'table_id': 130, 'total_records': None, 8969 'total_versions': None}, 8970 {'avg_fill': 44, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 2, 'data_pages': 2, 8971 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 187, 'indices': 0, 8972 'max_versions': None, 'name': 'EMPLOYEE', 'primary_pointer_page': 186, 'table_id': 131, 'total_records': None, 8973 'total_versions': None}, 8974 {'avg_fill': 20, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8975 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 196, 'indices': 0, 8976 'max_versions': None, 'name': 'EMPLOYEE_PROJECT', 'primary_pointer_page': 195, 'table_id': 135, 'total_records': None, 8977 'total_versions': None}, 8978 {'avg_fill': 73, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 3, 'data_pages': 3, 8979 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=2), 'index_root_page': 183, 'indices': 0, 8980 'max_versions': None, 'name': 'JOB', 'primary_pointer_page': 182, 'table_id': 129, 'total_records': None, 8981 'total_versions': None}, 8982 {'avg_fill': 29, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8983 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_root_page': 194, 'indices': 0, 8984 'max_versions': None, 'name': 'PROJECT', 'primary_pointer_page': 193, 'table_id': 134, 'total_records': None, 8985 'total_versions': None}, 8986 {'avg_fill': 80, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8987 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=1), 'index_root_page': 198, 'indices': 0, 8988 'max_versions': None, 'name': 'PROJ_DEPT_BUDGET', 'primary_pointer_page': 197, 'table_id': 136, 'total_records': None, 8989 'total_versions': None}, 8990 {'avg_fill': 58, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8991 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 200, 'indices': 0, 8992 'max_versions': None, 'name': 'SALARY_HISTORY', 'primary_pointer_page': 199, 'table_id': 137, 'total_records': None, 8993 'total_versions': None}, 8994 {'avg_fill': 68, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 8995 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 202, 'indices': 0, 8996 'max_versions': None, 'name': 'SALES', 'primary_pointer_page': 201, 'table_id': 138, 'total_records': None, 8997 'total_versions': None}, 8998 {'avg_fill': 0, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 0, 'data_pages': 0, 8999 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 282, 'indices': 0, 9000 'max_versions': None, 'name': 'T', 'primary_pointer_page': 205, 'table_id': 235, 'total_records': None, 9001 'total_versions': None}, 9002 {'avg_fill': 20, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9003 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 208, 'indices': 0, 9004 'max_versions': None, 'name': 'T2', 'primary_pointer_page': 207, 'table_id': 141, 'total_records': None, 9005 'total_versions': None}, 9006 {'avg_fill': 0, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 0, 'data_pages': 0, 9007 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 204, 'indices': 0, 9008 'max_versions': None, 'name': 'T3', 'primary_pointer_page': 203, 'table_id': 139, 'total_records': None, 9009 'total_versions': None}, 9010 {'avg_fill': 4, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9011 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 192, 'indices': 0, 9012 'max_versions': None, 'name': 'T4', 'primary_pointer_page': 191, 'table_id': 133, 'total_records': None, 9013 'total_versions': None}] 9014 i = 0 9015 while i < len(db.tables): 9016 self.assertDictEqual(data[i], get_object_data(db.tables[i]), 'Unexpected output from parser (tables)') 9017 i += 1 9018 # Indices 9019 self.assertEqual(len(db.indices), 0) 9020 def test_parse25_f(self): 9021 db = self._parse_file(os.path.join(self.dbpath, 'gstat25-f.out')) 9022 # 9023 self.assertTrue(db.has_table_stats()) 9024 self.assertTrue(db.has_index_stats()) 9025 self.assertTrue(db.has_row_stats()) 9026 self.assertFalse(db.has_encryption_stats()) 9027 self.assertTrue(db.has_system()) 9028 # Check system tables 9029 data = ['RDB$BACKUP_HISTORY', 'RDB$CHARACTER_SETS', 'RDB$CHECK_CONSTRAINTS', 'RDB$COLLATIONS', 'RDB$DATABASE', 'RDB$DEPENDENCIES', 9030 'RDB$EXCEPTIONS', 'RDB$FIELDS', 'RDB$FIELD_DIMENSIONS', 'RDB$FILES', 'RDB$FILTERS', 'RDB$FORMATS', 'RDB$FUNCTIONS', 9031 'RDB$FUNCTION_ARGUMENTS', 'RDB$GENERATORS', 'RDB$INDEX_SEGMENTS', 'RDB$INDICES', 'RDB$LOG_FILES', 'RDB$PAGES', 9032 'RDB$PROCEDURES', 'RDB$PROCEDURE_PARAMETERS', 'RDB$REF_CONSTRAINTS', 'RDB$RELATIONS', 'RDB$RELATION_CONSTRAINTS', 9033 'RDB$RELATION_FIELDS', 'RDB$ROLES', 'RDB$SECURITY_CLASSES', 'RDB$TRANSACTIONS', 'RDB$TRIGGERS', 'RDB$TRIGGER_MESSAGES', 9034 'RDB$TYPES', 'RDB$USER_PRIVILEGES', 'RDB$VIEW_RELATIONS'] 9035 for table in db.tables: 9036 if table.name.startswith('RDB$'): 9037 self.assertIn(table.name, data) 9038 # check system indices 9039 data = ['RDB$PRIMARY1', 'RDB$FOREIGN23', 'RDB$PRIMARY22', 'RDB$4', 'RDB$FOREIGN10', 'RDB$FOREIGN6', 'RDB$PRIMARY5', 'RDB$FOREIGN8', 9040 'RDB$FOREIGN9', 'RDB$PRIMARY7', 'RDB$FOREIGN15', 'RDB$FOREIGN16', 'RDB$PRIMARY14', 'RDB$FOREIGN3', 'RDB$PRIMARY2', 'RDB$11', 9041 'RDB$FOREIGN13', 'RDB$PRIMARY12', 'RDB$FOREIGN18', 'RDB$FOREIGN19', 'RDB$PRIMARY17', 'RDB$INDEX_44', 'RDB$INDEX_19', 9042 'RDB$INDEX_25', 'RDB$INDEX_14', 'RDB$INDEX_40', 'RDB$INDEX_20', 'RDB$INDEX_26', 'RDB$INDEX_27', 'RDB$INDEX_28', 9043 'RDB$INDEX_23', 'RDB$INDEX_24', 'RDB$INDEX_2', 'RDB$INDEX_36', 'RDB$INDEX_17', 'RDB$INDEX_45', 'RDB$INDEX_16', 'RDB$INDEX_9', 9044 'RDB$INDEX_10', 'RDB$INDEX_11', 'RDB$INDEX_46', 'RDB$INDEX_6', 'RDB$INDEX_31', 'RDB$INDEX_41', 'RDB$INDEX_5', 'RDB$INDEX_21', 9045 'RDB$INDEX_22', 'RDB$INDEX_18', 'RDB$INDEX_47', 'RDB$INDEX_48', 'RDB$INDEX_13', 'RDB$INDEX_0', 'RDB$INDEX_1', 'RDB$INDEX_12', 9046 'RDB$INDEX_42', 'RDB$INDEX_43', 'RDB$INDEX_15', 'RDB$INDEX_3', 'RDB$INDEX_4', 'RDB$INDEX_39', 'RDB$INDEX_7', 'RDB$INDEX_32', 9047 'RDB$INDEX_38', 'RDB$INDEX_8', 'RDB$INDEX_35', 'RDB$INDEX_37', 'RDB$INDEX_29', 'RDB$INDEX_30', 'RDB$INDEX_33', 'RDB$INDEX_34', 9048 'RDB$FOREIGN21', 'RDB$PRIMARY20', 'RDB$FOREIGN25', 'RDB$FOREIGN26', 'RDB$PRIMARY24', 'RDB$PRIMARY104'] 9049 for index in db.indices: 9050 if index.name.startswith('RDB$'): 9051 self.assertIn(index.name, data) 9052 def test_parse25_i(self): 9053 db = self._parse_file(os.path.join(self.dbpath, 'gstat25-i.out')) 9054 # 9055 self.assertFalse(db.has_table_stats()) 9056 self.assertTrue(db.has_index_stats()) 9057 self.assertFalse(db.has_row_stats()) 9058 self.assertFalse(db.has_encryption_stats()) 9059 # Tables 9060 data = [{'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9061 'distribution': None, 'index_root_page': None, 'indices': 0, 'max_versions': None, 'name': 'AR', 9062 'primary_pointer_page': None, 'table_id': 142, 'total_records': None, 'total_versions': None}, 9063 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9064 'distribution': None, 'index_root_page': None, 'indices': 1, 'max_versions': None, 'name': 'COUNTRY', 9065 'primary_pointer_page': None, 'table_id': 128, 'total_records': None, 'total_versions': None}, 9066 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9067 'distribution': None, 'index_root_page': None, 'indices': 4, 'max_versions': None, 'name': 'CUSTOMER', 9068 'primary_pointer_page': None, 'table_id': 132, 'total_records': None, 'total_versions': None}, 9069 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9070 'distribution': None, 'index_root_page': None, 'indices': 5, 'max_versions': None, 'name': 'DEPARTMENT', 9071 'primary_pointer_page': None, 'table_id': 130, 'total_records': None, 'total_versions': None}, 9072 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9073 'distribution': None, 'index_root_page': None, 'indices': 4, 'max_versions': None, 'name': 'EMPLOYEE', 9074 'primary_pointer_page': None, 'table_id': 131, 'total_records': None, 'total_versions': None}, 9075 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9076 'distribution': None, 'index_root_page': None, 'indices': 3, 'max_versions': None, 'name': 'EMPLOYEE_PROJECT', 9077 'primary_pointer_page': None, 'table_id': 135, 'total_records': None, 'total_versions': None}, 9078 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9079 'distribution': None, 'index_root_page': None, 'indices': 4, 'max_versions': None, 'name': 'JOB', 9080 'primary_pointer_page': None, 'table_id': 129, 'total_records': None, 'total_versions': None}, 9081 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9082 'distribution': None, 'index_root_page': None, 'indices': 4, 'max_versions': None, 'name': 'PROJECT', 9083 'primary_pointer_page': None, 'table_id': 134, 'total_records': None, 'total_versions': None}, 9084 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9085 'distribution': None, 'index_root_page': None, 'indices': 3, 'max_versions': None, 'name': 'PROJ_DEPT_BUDGET', 9086 'primary_pointer_page': None, 'table_id': 136, 'total_records': None, 'total_versions': None}, 9087 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9088 'distribution': None, 'index_root_page': None, 'indices': 4, 'max_versions': None, 'name': 'SALARY_HISTORY', 9089 'primary_pointer_page': None, 'table_id': 137, 'total_records': None, 'total_versions': None}, 9090 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9091 'distribution': None, 'index_root_page': None, 'indices': 6, 'max_versions': None, 'name': 'SALES', 9092 'primary_pointer_page': None, 'table_id': 138, 'total_records': None, 'total_versions': None}, 9093 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9094 'distribution': None, 'index_root_page': None, 'indices': 1, 'max_versions': None, 'name': 'T', 9095 'primary_pointer_page': None, 'table_id': 235, 'total_records': None, 'total_versions': None}, 9096 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9097 'distribution': None, 'index_root_page': None, 'indices': 0, 'max_versions': None, 'name': 'T2', 9098 'primary_pointer_page': None, 'table_id': 141, 'total_records': None, 'total_versions': None}, 9099 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9100 'distribution': None, 'index_root_page': None, 'indices': 0, 'max_versions': None, 'name': 'T3', 9101 'primary_pointer_page': None, 'table_id': 139, 'total_records': None, 'total_versions': None}, 9102 {'avg_fill': None, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': None, 'data_pages': None, 9103 'distribution': None, 'index_root_page': None, 'indices': 0, 'max_versions': None, 'name': 'T4', 9104 'primary_pointer_page': None, 'table_id': 133, 'total_records': None, 'total_versions': None}] 9105 i = 0 9106 while i < len(db.tables): 9107 self.assertDictEqual(data[i], get_object_data(db.tables[i]), 'Unexpected output from parser (tables)') 9108 i += 1 9109 # Indices 9110 #data = [] 9111 #for t in db.indices: 9112 #data.append(get_object_data(t, ['table'])) 9113 #pprint(data) 9114 data = [{'avg_data_length': 6.5, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9115 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY1', 'nodes': 14, 'total_dup': 0}, 9116 {'avg_data_length': 15.87, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9117 'leaf_buckets': 1, 'max_dup': 0, 'name': 'CUSTNAMEX', 'nodes': 15, 'total_dup': 0}, 9118 {'avg_data_length': 17.27, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9119 'leaf_buckets': 1, 'max_dup': 0, 'name': 'CUSTREGION', 'nodes': 15, 'total_dup': 0}, 9120 {'avg_data_length': 4.87, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9121 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN23', 'nodes': 15, 'total_dup': 4}, 9122 {'avg_data_length': 1.13, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9123 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY22', 'nodes': 15, 'total_dup': 0}, 9124 {'avg_data_length': 5.38, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9125 'leaf_buckets': 1, 'max_dup': 3, 'name': 'BUDGETX', 'nodes': 21, 'total_dup': 7}, 9126 {'avg_data_length': 13.95, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9127 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$4', 'nodes': 21, 'total_dup': 0}, 9128 {'avg_data_length': 1.14, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 9129 'leaf_buckets': 1, 'max_dup': 3, 'name': 'RDB$FOREIGN10', 'nodes': 21, 'total_dup': 3}, 9130 {'avg_data_length': 0.81, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9131 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN6', 'nodes': 21, 'total_dup': 13}, 9132 {'avg_data_length': 1.71, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9133 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY5', 'nodes': 21, 'total_dup': 0}, 9134 {'avg_data_length': 15.52, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_id': 1, 9135 'leaf_buckets': 1, 'max_dup': 0, 'name': 'NAMEX', 'nodes': 42, 'total_dup': 0}, 9136 {'avg_data_length': 0.81, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9137 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN8', 'nodes': 42, 'total_dup': 23}, 9138 {'avg_data_length': 6.79, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9139 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN9', 'nodes': 42, 'total_dup': 15}, 9140 {'avg_data_length': 1.31, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9141 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY7', 'nodes': 42, 'total_dup': 0}, 9142 {'avg_data_length': 1.04, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9143 'leaf_buckets': 1, 'max_dup': 2, 'name': 'RDB$FOREIGN15', 'nodes': 28, 'total_dup': 6}, 9144 {'avg_data_length': 0.86, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9145 'leaf_buckets': 1, 'max_dup': 9, 'name': 'RDB$FOREIGN16', 'nodes': 28, 'total_dup': 23}, 9146 {'avg_data_length': 9.11, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9147 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY14', 'nodes': 28, 'total_dup': 0}, 9148 {'avg_data_length': 10.9, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9149 'leaf_buckets': 1, 'max_dup': 1, 'name': 'MAXSALX', 'nodes': 31, 'total_dup': 5}, 9150 {'avg_data_length': 10.29, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9151 'leaf_buckets': 1, 'max_dup': 2, 'name': 'MINSALX', 'nodes': 31, 'total_dup': 7}, 9152 {'avg_data_length': 1.39, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9153 'leaf_buckets': 1, 'max_dup': 20, 'name': 'RDB$FOREIGN3', 'nodes': 31, 'total_dup': 24}, 9154 {'avg_data_length': 10.45, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9155 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY2', 'nodes': 31, 'total_dup': 0}, 9156 {'avg_data_length': 22.5, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9157 'leaf_buckets': 1, 'max_dup': 0, 'name': 'PRODTYPEX', 'nodes': 6, 'total_dup': 0}, 9158 {'avg_data_length': 13.33, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9159 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$11', 'nodes': 6, 'total_dup': 0}, 9160 {'avg_data_length': 1.33, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9161 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$FOREIGN13', 'nodes': 6, 'total_dup': 0}, 9162 {'avg_data_length': 4.83, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9163 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY12', 'nodes': 6, 'total_dup': 0}, 9164 {'avg_data_length': 0.71, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9165 'leaf_buckets': 1, 'max_dup': 5, 'name': 'RDB$FOREIGN18', 'nodes': 24, 'total_dup': 15}, 9166 {'avg_data_length': 1.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9167 'leaf_buckets': 1, 'max_dup': 8, 'name': 'RDB$FOREIGN19', 'nodes': 24, 'total_dup': 19}, 9168 {'avg_data_length': 6.83, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9169 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY17', 'nodes': 24, 'total_dup': 0}, 9170 {'avg_data_length': 0.31, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9171 'leaf_buckets': 1, 'max_dup': 21, 'name': 'CHANGEX', 'nodes': 49, 'total_dup': 46}, 9172 {'avg_data_length': 0.9, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9173 'leaf_buckets': 1, 'max_dup': 2, 'name': 'RDB$FOREIGN21', 'nodes': 49, 'total_dup': 16}, 9174 {'avg_data_length': 18.29, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_id': 0, 9175 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY20', 'nodes': 49, 'total_dup': 0}, 9176 {'avg_data_length': 0.29, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9177 'leaf_buckets': 1, 'max_dup': 28, 'name': 'UPDATERX', 'nodes': 49, 'total_dup': 46}, 9178 {'avg_data_length': 2.55, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9179 'leaf_buckets': 1, 'max_dup': 6, 'name': 'NEEDX', 'nodes': 33, 'total_dup': 11}, 9180 {'avg_data_length': 1.85, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9181 'leaf_buckets': 1, 'max_dup': 3, 'name': 'QTYX', 'nodes': 33, 'total_dup': 11}, 9182 {'avg_data_length': 0.52, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 9183 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN25', 'nodes': 33, 'total_dup': 18}, 9184 {'avg_data_length': 0.45, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 5, 9185 'leaf_buckets': 1, 'max_dup': 7, 'name': 'RDB$FOREIGN26', 'nodes': 33, 'total_dup': 25}, 9186 {'avg_data_length': 4.48, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9187 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY24', 'nodes': 33, 'total_dup': 0}, 9188 {'avg_data_length': 0.97, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9189 'leaf_buckets': 1, 'max_dup': 14, 'name': 'SALESTATX', 'nodes': 33, 'total_dup': 27}, 9190 {'avg_data_length': 0.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9191 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY104', 'nodes': 0, 'total_dup': 0}] 9192 i = 0 9193 while i < len(db.tables): 9194 self.assertDictEqual(data[i], get_object_data(db.indices[i], ['table']), 'Unexpected output from parser (indices)') 9195 i += 1 9196 def test_parse25_r(self): 9197 db = self._parse_file(os.path.join(self.dbpath, 'gstat25-r.out')) 9198 # 9199 self.assertTrue(db.has_table_stats()) 9200 self.assertTrue(db.has_index_stats()) 9201 self.assertTrue(db.has_row_stats()) 9202 self.assertFalse(db.has_encryption_stats()) 9203 self.assertFalse(db.has_system()) 9204 # Tables 9205 data = [{'avg_fill': 86, 'avg_record_length': 22.07, 'avg_version_length': 0.0, 'data_page_slots': 1, 'data_pages': 1, 9206 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=1), 'index_root_page': 210, 'indices': 0, 9207 'max_versions': 0, 'name': 'AR', 'primary_pointer_page': 209, 'table_id': 142, 'total_records': 15, 'total_versions': 0}, 9208 {'avg_fill': 15, 'avg_record_length': 26.86, 'avg_version_length': 0.0, 'data_page_slots': 1, 'data_pages': 1, 9209 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 181, 'indices': 1, 9210 'max_versions': 0, 'name': 'COUNTRY', 'primary_pointer_page': 180, 'table_id': 128, 'total_records': 14, 'total_versions': 0}, 9211 {'avg_fill': 53, 'avg_record_length': 126.47, 'avg_version_length': 0.0, 'data_page_slots': 1, 'data_pages': 1, 9212 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 189, 'indices': 4, 9213 'max_versions': 0, 'name': 'CUSTOMER', 'primary_pointer_page': 188, 'table_id': 132, 'total_records': 15, 'total_versions': 0}, 9214 {'avg_fill': 47, 'avg_record_length': 73.62, 'avg_version_length': 0.0, 'data_page_slots': 1, 'data_pages': 1, 9215 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 185, 'indices': 5, 9216 'max_versions': 0, 'name': 'DEPARTMENT', 'primary_pointer_page': 184, 'table_id': 130, 'total_records': 21, 'total_versions': 0}, 9217 {'avg_fill': 44, 'avg_record_length': 68.86, 'avg_version_length': 0.0, 'data_page_slots': 2, 'data_pages': 2, 9218 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 187, 'indices': 4, 9219 'max_versions': 0, 'name': 'EMPLOYEE', 'primary_pointer_page': 186, 'table_id': 131, 'total_records': 42, 'total_versions': 0}, 9220 {'avg_fill': 20, 'avg_record_length': 12.0, 'avg_version_length': 0.0, 'data_page_slots': 1, 'data_pages': 1, 9221 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 196, 'indices': 3, 9222 'max_versions': 0, 'name': 'EMPLOYEE_PROJECT', 'primary_pointer_page': 195, 'table_id': 135, 'total_records': 28, 'total_versions': 0}, 9223 {'avg_fill': 73, 'avg_record_length': 67.13, 'avg_version_length': 0.0, 'data_page_slots': 3, 'data_pages': 3, 9224 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=2), 'index_root_page': 183, 'indices': 4, 9225 'max_versions': 0, 'name': 'JOB', 'primary_pointer_page': 182, 'table_id': 129, 'total_records': 31, 'total_versions': 0}, 9226 {'avg_fill': 29, 'avg_record_length': 48.83, 'avg_version_length': 0.0, 'data_page_slots': 1, 'data_pages': 1, 9227 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_root_page': 194, 'indices': 4, 9228 'max_versions': 0, 'name': 'PROJECT', 'primary_pointer_page': 193, 'table_id': 134, 'total_records': 6, 'total_versions': 0}, 9229 {'avg_fill': 80, 'avg_record_length': 30.96, 'avg_version_length': 0.0, 'data_page_slots': 1, 'data_pages': 1, 9230 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=1), 'index_root_page': 198, 'indices': 3, 9231 'max_versions': 0, 'name': 'PROJ_DEPT_BUDGET', 'primary_pointer_page': 197, 'table_id': 136, 'total_records': 24, 9232 'total_versions': 0}, 9233 {'avg_fill': 58, 'avg_record_length': 31.51, 'avg_version_length': 0.0, 'data_page_slots': 1, 'data_pages': 1, 9234 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 200, 'indices': 4, 9235 'max_versions': 0, 'name': 'SALARY_HISTORY', 'primary_pointer_page': 199, 'table_id': 137, 'total_records': 49, 'total_versions': 0}, 9236 {'avg_fill': 68, 'avg_record_length': 67.24, 'avg_version_length': 0.0, 'data_page_slots': 1, 'data_pages': 1, 9237 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 202, 'indices': 6, 9238 'max_versions': 0, 'name': 'SALES', 'primary_pointer_page': 201, 'table_id': 138, 'total_records': 33, 'total_versions': 0}, 9239 {'avg_fill': 0, 'avg_record_length': 0.0, 'avg_version_length': 0.0, 'data_page_slots': 0, 'data_pages': 0, 9240 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 282, 'indices': 1, 9241 'max_versions': 0, 'name': 'T', 'primary_pointer_page': 205, 'table_id': 235, 'total_records': 0, 'total_versions': 0}, 9242 {'avg_fill': 20, 'avg_record_length': 0.0, 'avg_version_length': 17.0, 'data_page_slots': 1, 'data_pages': 1, 9243 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 208, 'indices': 0, 9244 'max_versions': 1, 'name': 'T2', 'primary_pointer_page': 207, 'table_id': 141, 'total_records': 2, 'total_versions': 2}, 9245 {'avg_fill': 0, 'avg_record_length': 0.0, 'avg_version_length': 0.0, 'data_page_slots': 0, 'data_pages': 0, 9246 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 204, 'indices': 0, 9247 'max_versions': 0, 'name': 'T3', 'primary_pointer_page': 203, 'table_id': 139, 'total_records': 0, 'total_versions': 0}, 9248 {'avg_fill': 4, 'avg_record_length': 0.0, 'avg_version_length': 129.0, 'data_page_slots': 1, 'data_pages': 1, 9249 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 192, 'indices': 0, 9250 'max_versions': 1, 'name': 'T4', 'primary_pointer_page': 191, 'table_id': 133, 'total_records': 1, 'total_versions': 1}] 9251 i = 0 9252 while i < len(db.tables): 9253 self.assertDictEqual(data[i], get_object_data(db.tables[i]), 'Unexpected output from parser (tables)') 9254 i += 1 9255 # Indices 9256 data = [{'avg_data_length': 6.5, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9257 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY1', 'nodes': 14, 'total_dup': 0}, 9258 {'avg_data_length': 15.87, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9259 'leaf_buckets': 1, 'max_dup': 0, 'name': 'CUSTNAMEX', 'nodes': 15, 'total_dup': 0}, 9260 {'avg_data_length': 17.27, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9261 'leaf_buckets': 1, 'max_dup': 0, 'name': 'CUSTREGION', 'nodes': 15, 'total_dup': 0}, 9262 {'avg_data_length': 4.87, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9263 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN23', 'nodes': 15, 'total_dup': 4}, 9264 {'avg_data_length': 1.13, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9265 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY22', 'nodes': 15, 'total_dup': 0}, 9266 {'avg_data_length': 5.38, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9267 'leaf_buckets': 1, 'max_dup': 3, 'name': 'BUDGETX', 'nodes': 21, 'total_dup': 7}, 9268 {'avg_data_length': 13.95, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9269 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$4', 'nodes': 21, 'total_dup': 0}, 9270 {'avg_data_length': 1.14, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 9271 'leaf_buckets': 1, 'max_dup': 3, 'name': 'RDB$FOREIGN10', 'nodes': 21, 'total_dup': 3}, 9272 {'avg_data_length': 0.81, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9273 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN6', 'nodes': 21, 'total_dup': 13}, 9274 {'avg_data_length': 1.71, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9275 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY5', 'nodes': 21, 'total_dup': 0}, 9276 {'avg_data_length': 15.52, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_id': 1, 9277 'leaf_buckets': 1, 'max_dup': 0, 'name': 'NAMEX', 'nodes': 42, 'total_dup': 0}, 9278 {'avg_data_length': 0.81, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9279 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN8', 'nodes': 42, 'total_dup': 23}, 9280 {'avg_data_length': 6.79, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9281 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN9', 'nodes': 42, 'total_dup': 15}, 9282 {'avg_data_length': 1.31, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9283 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY7', 'nodes': 42, 'total_dup': 0}, 9284 {'avg_data_length': 1.04, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9285 'leaf_buckets': 1, 'max_dup': 2, 'name': 'RDB$FOREIGN15', 'nodes': 28, 'total_dup': 6}, 9286 {'avg_data_length': 0.86, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9287 'leaf_buckets': 1, 'max_dup': 9, 'name': 'RDB$FOREIGN16', 'nodes': 28, 'total_dup': 23}, 9288 {'avg_data_length': 9.11, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9289 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY14', 'nodes': 28, 'total_dup': 0}, 9290 {'avg_data_length': 10.9, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9291 'leaf_buckets': 1, 'max_dup': 1, 'name': 'MAXSALX', 'nodes': 31, 'total_dup': 5}, 9292 {'avg_data_length': 10.29, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9293 'leaf_buckets': 1, 'max_dup': 2, 'name': 'MINSALX', 'nodes': 31, 'total_dup': 7}, 9294 {'avg_data_length': 1.39, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9295 'leaf_buckets': 1, 'max_dup': 20, 'name': 'RDB$FOREIGN3', 'nodes': 31, 'total_dup': 24}, 9296 {'avg_data_length': 10.45, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9297 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY2', 'nodes': 31, 'total_dup': 0}, 9298 {'avg_data_length': 22.5, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9299 'leaf_buckets': 1, 'max_dup': 0, 'name': 'PRODTYPEX', 'nodes': 6, 'total_dup': 0}, 9300 {'avg_data_length': 13.33, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9301 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$11', 'nodes': 6, 'total_dup': 0}, 9302 {'avg_data_length': 1.33, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9303 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$FOREIGN13', 'nodes': 6, 'total_dup': 0}, 9304 {'avg_data_length': 4.83, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9305 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY12', 'nodes': 6, 'total_dup': 0}, 9306 {'avg_data_length': 0.71, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9307 'leaf_buckets': 1, 'max_dup': 5, 'name': 'RDB$FOREIGN18', 'nodes': 24, 'total_dup': 15}, 9308 {'avg_data_length': 1.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9309 'leaf_buckets': 1, 'max_dup': 8, 'name': 'RDB$FOREIGN19', 'nodes': 24, 'total_dup': 19}, 9310 {'avg_data_length': 6.83, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9311 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY17', 'nodes': 24, 'total_dup': 0}, 9312 {'avg_data_length': 0.31, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9313 'leaf_buckets': 1, 'max_dup': 21, 'name': 'CHANGEX', 'nodes': 49, 'total_dup': 46}, 9314 {'avg_data_length': 0.9, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9315 'leaf_buckets': 1, 'max_dup': 2, 'name': 'RDB$FOREIGN21', 'nodes': 49, 'total_dup': 16}, 9316 {'avg_data_length': 18.29, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_id': 0, 9317 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY20', 'nodes': 49, 'total_dup': 0}, 9318 {'avg_data_length': 0.29, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9319 'leaf_buckets': 1, 'max_dup': 28, 'name': 'UPDATERX', 'nodes': 49, 'total_dup': 46}, 9320 {'avg_data_length': 2.55, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 9321 'leaf_buckets': 1, 'max_dup': 6, 'name': 'NEEDX', 'nodes': 33, 'total_dup': 11}, 9322 {'avg_data_length': 1.85, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 9323 'leaf_buckets': 1, 'max_dup': 3, 'name': 'QTYX', 'nodes': 33, 'total_dup': 11}, 9324 {'avg_data_length': 0.52, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 9325 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN25', 'nodes': 33, 'total_dup': 18}, 9326 {'avg_data_length': 0.45, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 5, 9327 'leaf_buckets': 1, 'max_dup': 7, 'name': 'RDB$FOREIGN26', 'nodes': 33, 'total_dup': 25}, 9328 {'avg_data_length': 4.48, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9329 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY24', 'nodes': 33, 'total_dup': 0}, 9330 {'avg_data_length': 0.97, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 9331 'leaf_buckets': 1, 'max_dup': 14, 'name': 'SALESTATX', 'nodes': 33, 'total_dup': 27}, 9332 {'avg_data_length': 0.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 9333 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY104', 'nodes': 0, 'total_dup': 0}] 9334 i = 0 9335 while i < len(db.tables): 9336 self.assertDictEqual(data[i], get_object_data(db.indices[i], ['table']), 'Unexpected output from parser (indices)') 9337 i += 1 9338 def test_parse25_s(self): 9339 db = self._parse_file(os.path.join(self.dbpath, 'gstat25-s.out')) 9340 # 9341 self.assertTrue(db.has_table_stats()) 9342 self.assertTrue(db.has_index_stats()) 9343 self.assertFalse(db.has_row_stats()) 9344 self.assertFalse(db.has_encryption_stats()) 9345 self.assertTrue(db.has_system()) 9346 # Tables 9347 data = [{'avg_fill': 86, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9348 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=1), 'index_root_page': 210, 'indices': 0, 9349 'max_versions': None, 'name': 'AR', 'primary_pointer_page': 209, 'table_id': 142, 'total_records': None, 'total_versions': None}, 9350 {'avg_fill': 15, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9351 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 181, 'indices': 1, 9352 'max_versions': None, 'name': 'COUNTRY', 'primary_pointer_page': 180, 'table_id': 128, 'total_records': None, 'total_versions': None}, 9353 {'avg_fill': 53, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9354 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 189, 'indices': 4, 9355 'max_versions': None, 'name': 'CUSTOMER', 'primary_pointer_page': 188, 'table_id': 132, 'total_records': None, 9356 'total_versions': None}, 9357 {'avg_fill': 47, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9358 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 185, 'indices': 5, 9359 'max_versions': None, 'name': 'DEPARTMENT', 'primary_pointer_page': 184, 'table_id': 130, 'total_records': None, 9360 'total_versions': None}, 9361 {'avg_fill': 44, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 2, 'data_pages': 2, 9362 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 187, 'indices': 4, 9363 'max_versions': None, 'name': 'EMPLOYEE', 'primary_pointer_page': 186, 'table_id': 131, 'total_records': None, 9364 'total_versions': None}, 9365 {'avg_fill': 20, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9366 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 196, 'indices': 3, 9367 'max_versions': None, 'name': 'EMPLOYEE_PROJECT', 'primary_pointer_page': 195, 'table_id': 135, 'total_records': None, 9368 'total_versions': None}, 9369 {'avg_fill': 73, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 3, 'data_pages': 3, 9370 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=2), 'index_root_page': 183, 'indices': 4, 9371 'max_versions': None, 'name': 'JOB', 'primary_pointer_page': 182, 'table_id': 129, 'total_records': None, 9372 'total_versions': None}, 9373 {'avg_fill': 29, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9374 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_root_page': 194, 'indices': 4, 9375 'max_versions': None, 'name': 'PROJECT', 'primary_pointer_page': 193, 'table_id': 134, 'total_records': None, 9376 'total_versions': None}, 9377 {'avg_fill': 80, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9378 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=1), 'index_root_page': 198, 'indices': 3, 9379 'max_versions': None, 'name': 'PROJ_DEPT_BUDGET', 'primary_pointer_page': 197, 'table_id': 136, 'total_records': None, 9380 'total_versions': None}, 9381 {'avg_fill': 0, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 0, 'data_pages': 0, 9382 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 69, 'indices': 1, 9383 'max_versions': None, 'name': 'RDB$BACKUP_HISTORY', 'primary_pointer_page': 68, 'table_id': 32, 'total_records': None, 9384 'total_versions': None}, 9385 {'avg_fill': 69, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9386 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 61, 'indices': 2, 9387 'max_versions': None, 'name': 'RDB$CHARACTER_SETS', 'primary_pointer_page': 60, 'table_id': 28, 'total_records': None, 9388 'total_versions': None}, 9389 {'avg_fill': 37, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 2, 'data_pages': 2, 9390 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 53, 'indices': 2, 9391 'max_versions': None, 'name': 'RDB$CHECK_CONSTRAINTS', 'primary_pointer_page': 52, 'table_id': 24, 'total_records': None, 9392 'total_versions': None}, 9393 {'avg_fill': 55, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 3, 'data_pages': 3, 9394 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=2, d100=0), 'index_root_page': 63, 'indices': 2, 9395 'max_versions': None, 'name': 'RDB$COLLATIONS', 'primary_pointer_page': 62, 'table_id': 29, 'total_records': None, 9396 'total_versions': None}, 9397 {'avg_fill': 1, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9398 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 7, 'indices': 0, 9399 'max_versions': None, 'name': 'RDB$DATABASE', 'primary_pointer_page': 6, 'table_id': 1, 'total_records': None, 9400 'total_versions': None}, 9401 {'avg_fill': 49, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 6, 'data_pages': 5, 9402 'distribution': FillDistribution(d20=1, d40=1, d50=1, d80=2, d100=0), 'index_root_page': 31, 'indices': 2, 9403 'max_versions': None, 'name': 'RDB$DEPENDENCIES', 'primary_pointer_page': 30, 'table_id': 13, 'total_records': None, 9404 'total_versions': None}, 9405 {'avg_fill': 12, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9406 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 65, 'indices': 2, 9407 'max_versions': None, 'name': 'RDB$EXCEPTIONS', 'primary_pointer_page': 64, 'table_id': 30, 'total_records': None, 9408 'total_versions': None}, 9409 {'avg_fill': 62, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 6, 'data_pages': 6, 9410 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=4, d100=1), 'index_root_page': 9, 'indices': 1, 9411 'max_versions': None, 'name': 'RDB$FIELDS', 'primary_pointer_page': 8, 'table_id': 2, 'total_records': None, 9412 'total_versions': None}, 9413 {'avg_fill': 19, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9414 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 47, 'indices': 1, 9415 'max_versions': None, 'name': 'RDB$FIELD_DIMENSIONS', 'primary_pointer_page': 46, 'table_id': 21, 'total_records': None, 9416 'total_versions': None}, 9417 {'avg_fill': 0, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 0, 'data_pages': 0, 9418 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 25, 'indices': 0, 9419 'max_versions': None, 'name': 'RDB$FILES', 'primary_pointer_page': 24, 'table_id': 10, 'total_records': None, 9420 'total_versions': None}, 9421 {'avg_fill': 0, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 0, 'data_pages': 0, 9422 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 37, 'indices': 2, 9423 'max_versions': None, 'name': 'RDB$FILTERS', 'primary_pointer_page': 36, 'table_id': 16, 'total_records': None, 9424 'total_versions': None}, 9425 {'avg_fill': 76, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9426 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 21, 'indices': 1, 9427 'max_versions': None, 'name': 'RDB$FORMATS', 'primary_pointer_page': 20, 'table_id': 8, 'total_records': None, 9428 'total_versions': None}, 9429 {'avg_fill': 4, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9430 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 33, 'indices': 1, 9431 'max_versions': None, 'name': 'RDB$FUNCTIONS', 'primary_pointer_page': 32, 'table_id': 14, 'total_records': None, 9432 'total_versions': None}, 9433 {'avg_fill': 9, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9434 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 35, 'indices': 1, 9435 'max_versions': None, 'name': 'RDB$FUNCTION_ARGUMENTS', 'primary_pointer_page': 34, 'table_id': 15, 'total_records': None, 9436 'total_versions': None}, 9437 {'avg_fill': 22, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9438 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_root_page': 45, 'indices': 2, 9439 'max_versions': None, 'name': 'RDB$GENERATORS', 'primary_pointer_page': 44, 'table_id': 20, 'total_records': None, 9440 'total_versions': None}, 9441 {'avg_fill': 79, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 3, 'data_pages': 3, 9442 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=2, d100=1), 'index_root_page': 11, 'indices': 1, 9443 'max_versions': None, 'name': 'RDB$INDEX_SEGMENTS', 'primary_pointer_page': 10, 'table_id': 3, 'total_records': None, 9444 'total_versions': None}, 9445 {'avg_fill': 48, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 4, 'data_pages': 4, 9446 'distribution': FillDistribution(d20=1, d40=1, d50=0, d80=2, d100=0), 'index_root_page': 13, 'indices': 3, 9447 'max_versions': None, 'name': 'RDB$INDICES', 'primary_pointer_page': 12, 'table_id': 4, 'total_records': None, 9448 'total_versions': None}, 9449 {'avg_fill': 0, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 0, 'data_pages': 0, 9450 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 55, 'indices': 0, 9451 'max_versions': None, 'name': 'RDB$LOG_FILES', 'primary_pointer_page': 54, 'table_id': 25, 'total_records': None, 9452 'total_versions': None}, 9453 {'avg_fill': 38, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 2, 'data_pages': 2, 9454 'distribution': FillDistribution(d20=1, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 4, 'indices': 0, 9455 'max_versions': None, 'name': 'RDB$PAGES', 'primary_pointer_page': 3, 'table_id': 0, 'total_records': None, 9456 'total_versions': None}, 9457 {'avg_fill': 94, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 3, 'data_pages': 3, 9458 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=3), 'index_root_page': 57, 'indices': 2, 9459 'max_versions': None, 'name': 'RDB$PROCEDURES', 'primary_pointer_page': 56, 'table_id': 26, 'total_records': None, 9460 'total_versions': None}, 9461 {'avg_fill': 48, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9462 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 59, 'indices': 3, 9463 'max_versions': None, 'name': 'RDB$PROCEDURE_PARAMETERS', 'primary_pointer_page': 58, 'table_id': 27, 9464 'total_records': None, 'total_versions': None}, 9465 {'avg_fill': 25, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9466 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 'index_root_page': 51, 'indices': 1, 9467 'max_versions': None, 'name': 'RDB$REF_CONSTRAINTS', 'primary_pointer_page': 50, 'table_id': 23, 'total_records': None, 9468 'total_versions': None}, 9469 {'avg_fill': 71, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 6, 'data_pages': 5, 9470 'distribution': FillDistribution(d20=0, d40=0, d50=2, d80=1, d100=2), 'index_root_page': 17, 'indices': 2, 9471 'max_versions': None, 'name': 'RDB$RELATIONS', 'primary_pointer_page': 16, 'table_id': 6, 'total_records': None, 9472 'total_versions': None}, 9473 {'avg_fill': 67, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 2, 'data_pages': 2, 9474 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=2, d100=0), 'index_root_page': 49, 'indices': 3, 9475 'max_versions': None, 'name': 'RDB$RELATION_CONSTRAINTS', 'primary_pointer_page': 48, 'table_id': 22, 9476 'total_records': None, 'total_versions': None}, 9477 {'avg_fill': 77, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 13, 'data_pages': 13, 9478 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=9, d100=3), 'index_root_page': 15, 'indices': 3, 9479 'max_versions': None, 'name': 'RDB$RELATION_FIELDS', 'primary_pointer_page': 14, 'table_id': 5, 'total_records': None, 9480 'total_versions': None}, 9481 {'avg_fill': 2, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9482 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 67, 'indices': 1, 9483 'max_versions': None, 'name': 'RDB$ROLES', 'primary_pointer_page': 66, 'table_id': 31, 'total_records': None, 9484 'total_versions': None}, 9485 {'avg_fill': 77, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 6, 'data_pages': 6, 9486 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=1, d100=4), 'index_root_page': 23, 'indices': 1, 9487 'max_versions': None, 'name': 'RDB$SECURITY_CLASSES', 'primary_pointer_page': 22, 'table_id': 9, 'total_records': None, 9488 'total_versions': None}, 9489 {'avg_fill': 0, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 0, 'data_pages': 0, 9490 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 43, 'indices': 1, 9491 'max_versions': None, 'name': 'RDB$TRANSACTIONS', 'primary_pointer_page': 42, 'table_id': 19, 'total_records': None, 9492 'total_versions': None}, 9493 {'avg_fill': 90, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 7, 'data_pages': 7, 9494 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=2, d100=5), 'index_root_page': 29, 'indices': 2, 9495 'max_versions': None, 'name': 'RDB$TRIGGERS', 'primary_pointer_page': 28, 'table_id': 12, 'total_records': None, 9496 'total_versions': None}, 9497 {'avg_fill': 68, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9498 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 39, 'indices': 1, 9499 'max_versions': None, 'name': 'RDB$TRIGGER_MESSAGES', 'primary_pointer_page': 38, 'table_id': 17, 'total_records': None, 9500 'total_versions': None}, 9501 {'avg_fill': 70, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 5, 'data_pages': 5, 9502 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=5, d100=0), 'index_root_page': 27, 'indices': 1, 9503 'max_versions': None, 'name': 'RDB$TYPES', 'primary_pointer_page': 26, 'table_id': 11, 'total_records': None, 9504 'total_versions': None}, 9505 {'avg_fill': 67, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 4, 'data_pages': 4, 9506 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=3, d100=0), 'index_root_page': 41, 'indices': 2, 9507 'max_versions': None, 'name': 'RDB$USER_PRIVILEGES', 'primary_pointer_page': 40, 'table_id': 18, 'total_records': None, 9508 'total_versions': None}, 9509 {'avg_fill': 3, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9510 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 19, 'indices': 2, 9511 'max_versions': None, 'name': 'RDB$VIEW_RELATIONS', 'primary_pointer_page': 18, 'table_id': 7, 'total_records': None, 9512 'total_versions': None}, 9513 {'avg_fill': 58, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9514 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 'index_root_page': 200, 'indices': 4, 9515 'max_versions': None, 'name': 'SALARY_HISTORY', 'primary_pointer_page': 199, 'table_id': 137, 'total_records': None, 9516 'total_versions': None}, 9517 {'avg_fill': 68, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9518 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=1, d100=0), 'index_root_page': 202, 'indices': 6, 9519 'max_versions': None, 'name': 'SALES', 'primary_pointer_page': 201, 'table_id': 138, 'total_records': None, 9520 'total_versions': None}, 9521 {'avg_fill': 0, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 0, 'data_pages': 0, 9522 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 282, 'indices': 1, 9523 'max_versions': None, 'name': 'T', 'primary_pointer_page': 205, 'table_id': 235, 'total_records': None, 'total_versions': None}, 9524 {'avg_fill': 20, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9525 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 208, 'indices': 0, 9526 'max_versions': None, 'name': 'T2', 'primary_pointer_page': 207, 'table_id': 141, 'total_records': None, 'total_versions': None}, 9527 {'avg_fill': 0, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 0, 'data_pages': 0, 9528 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 204, 'indices': 0, 9529 'max_versions': None, 'name': 'T3', 'primary_pointer_page': 203, 'table_id': 139, 'total_records': None, 'total_versions': None}, 9530 {'avg_fill': 4, 'avg_record_length': None, 'avg_version_length': None, 'data_page_slots': 1, 'data_pages': 1, 9531 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_root_page': 192, 'indices': 0, 9532 'max_versions': None, 'name': 'T4', 'primary_pointer_page': 191, 'table_id': 133, 'total_records': None, 'total_versions': None}] 9533 i = 0 9534 while i < len(db.tables): 9535 self.assertDictEqual(data[i], get_object_data(db.tables[i]), 'Unexpected output from parser (tables)') 9536 i += 1 9537 # Indices 9538 data = [{'avg_data_length': 6.5, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9539 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY1', 'nodes': 14, 'total_dup': 0}, 9540 {'avg_data_length': 15.87, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9541 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'CUSTNAMEX', 'nodes': 15, 'total_dup': 0}, 9542 {'avg_data_length': 17.27, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9543 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'CUSTREGION', 'nodes': 15, 'total_dup': 0}, 9544 {'avg_data_length': 4.87, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9545 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN23', 'nodes': 15, 'total_dup': 4}, 9546 {'avg_data_length': 1.13, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9547 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY22', 'nodes': 15, 'total_dup': 0}, 9548 {'avg_data_length': 5.38, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9549 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 3, 'name': 'BUDGETX', 'nodes': 21, 'total_dup': 7}, 9550 {'avg_data_length': 13.95, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9551 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$4', 'nodes': 21, 'total_dup': 0}, 9552 {'avg_data_length': 1.14, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9553 'index_id': 4, 'leaf_buckets': 1, 'max_dup': 3, 'name': 'RDB$FOREIGN10', 'nodes': 21, 'total_dup': 3}, 9554 {'avg_data_length': 0.81, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9555 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN6', 'nodes': 21, 'total_dup': 13}, 9556 {'avg_data_length': 1.71, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9557 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY5', 'nodes': 21, 'total_dup': 0}, 9558 {'avg_data_length': 15.52, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 9559 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'NAMEX', 'nodes': 42, 'total_dup': 0}, 9560 {'avg_data_length': 0.81, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9561 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN8', 'nodes': 42, 'total_dup': 23}, 9562 {'avg_data_length': 6.79, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9563 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN9', 'nodes': 42, 'total_dup': 15}, 9564 {'avg_data_length': 1.31, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9565 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY7', 'nodes': 42, 'total_dup': 0}, 9566 {'avg_data_length': 1.04, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9567 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 2, 'name': 'RDB$FOREIGN15', 'nodes': 28, 'total_dup': 6}, 9568 {'avg_data_length': 0.86, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9569 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 9, 'name': 'RDB$FOREIGN16', 'nodes': 28, 'total_dup': 23}, 9570 {'avg_data_length': 9.11, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9571 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY14', 'nodes': 28, 'total_dup': 0}, 9572 {'avg_data_length': 10.9, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9573 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 1, 'name': 'MAXSALX', 'nodes': 31, 'total_dup': 5}, 9574 {'avg_data_length': 10.29, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9575 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 2, 'name': 'MINSALX', 'nodes': 31, 'total_dup': 7}, 9576 {'avg_data_length': 1.39, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9577 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 20, 'name': 'RDB$FOREIGN3', 'nodes': 31, 'total_dup': 24}, 9578 {'avg_data_length': 10.45, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9579 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY2', 'nodes': 31, 'total_dup': 0}, 9580 {'avg_data_length': 22.5, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9581 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'PRODTYPEX', 'nodes': 6, 'total_dup': 0}, 9582 {'avg_data_length': 13.33, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9583 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$11', 'nodes': 6, 'total_dup': 0}, 9584 {'avg_data_length': 1.33, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9585 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$FOREIGN13', 'nodes': 6, 'total_dup': 0}, 9586 {'avg_data_length': 4.83, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9587 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY12', 'nodes': 6, 'total_dup': 0}, 9588 {'avg_data_length': 0.71, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9589 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 5, 'name': 'RDB$FOREIGN18', 'nodes': 24, 'total_dup': 15}, 9590 {'avg_data_length': 1.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9591 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 8, 'name': 'RDB$FOREIGN19', 'nodes': 24, 'total_dup': 19}, 9592 {'avg_data_length': 6.83, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9593 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY17', 'nodes': 24, 'total_dup': 0}, 9594 {'avg_data_length': 0.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9595 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_44', 'nodes': 0, 'total_dup': 0}, 9596 {'avg_data_length': 2.98, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9597 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_19', 'nodes': 52, 'total_dup': 0}, 9598 {'avg_data_length': 1.04, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9599 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_25', 'nodes': 52, 'total_dup': 0}, 9600 {'avg_data_length': 0.9, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9601 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 1, 'name': 'RDB$INDEX_14', 'nodes': 70, 'total_dup': 14}, 9602 {'avg_data_length': 3.81, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9603 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 2, 'name': 'RDB$INDEX_40', 'nodes': 70, 'total_dup': 11}, 9604 {'avg_data_length': 3.77, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 9605 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_20', 'nodes': 149, 'total_dup': 0}, 9606 {'avg_data_length': 1.79, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9607 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_26', 'nodes': 149, 'total_dup': 0}, 9608 {'avg_data_length': 1.18, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9609 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 13, 'name': 'RDB$INDEX_27', 'nodes': 163, 'total_dup': 118}, 9610 {'avg_data_length': 1.01, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9611 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 36, 'name': 'RDB$INDEX_28', 'nodes': 163, 'total_dup': 145}, 9612 {'avg_data_length': 14.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9613 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_23', 'nodes': 5, 'total_dup': 0}, 9614 {'avg_data_length': 1.2, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9615 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_24', 'nodes': 5, 'total_dup': 0}, 9616 {'avg_data_length': 4.58, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 9617 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_2', 'nodes': 245, 'total_dup': 0}, 9618 {'avg_data_length': 1.26, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9619 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 2, 'name': 'RDB$INDEX_36', 'nodes': 19, 'total_dup': 3}, 9620 {'avg_data_length': 0.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9621 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_17', 'nodes': 0, 'total_dup': 0}, 9622 {'avg_data_length': 0.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9623 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_45', 'nodes': 0, 'total_dup': 0}, 9624 {'avg_data_length': 4.63, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9625 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_16', 'nodes': 19, 'total_dup': 0}, 9626 {'avg_data_length': 13.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9627 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_9', 'nodes': 2, 'total_dup': 0}, 9628 {'avg_data_length': 3.71, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9629 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 3, 'name': 'RDB$INDEX_10', 'nodes': 7, 'total_dup': 5}, 9630 {'avg_data_length': 11.91, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9631 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_11', 'nodes': 11, 'total_dup': 0}, 9632 {'avg_data_length': 1.09, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9633 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_46', 'nodes': 11, 'total_dup': 0}, 9634 {'avg_data_length': 1.5, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9635 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 2, 'name': 'RDB$INDEX_6', 'nodes': 150, 'total_dup': 24}, 9636 {'avg_data_length': 4.23, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9637 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 5, 'name': 'RDB$INDEX_31', 'nodes': 88, 'total_dup': 48}, 9638 {'avg_data_length': 0.19, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9639 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 73, 'name': 'RDB$INDEX_41', 'nodes': 88, 'total_dup': 81}, 9640 {'avg_data_length': 2.09, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9641 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_5', 'nodes': 88, 'total_dup': 0}, 9642 {'avg_data_length': 10.6, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9643 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_21', 'nodes': 10, 'total_dup': 0}, 9644 {'avg_data_length': 1.1, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9645 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_22', 'nodes': 10, 'total_dup': 0}, 9646 {'avg_data_length': 11.33, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9647 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_18', 'nodes': 33, 'total_dup': 0}, 9648 {'avg_data_length': 1.24, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9649 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_47', 'nodes': 33, 'total_dup': 0}, 9650 {'avg_data_length': 0.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9651 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 32, 'name': 'RDB$INDEX_48', 'nodes': 33, 'total_dup': 32}, 9652 {'avg_data_length': 1.93, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9653 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_13', 'nodes': 14, 'total_dup': 0}, 9654 {'avg_data_length': 8.81, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9655 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_0', 'nodes': 58, 'total_dup': 0}, 9656 {'avg_data_length': 0.82, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9657 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 14, 'name': 'RDB$INDEX_1', 'nodes': 73, 'total_dup': 14}, 9658 {'avg_data_length': 1.07, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9659 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_12', 'nodes': 82, 'total_dup': 0}, 9660 {'avg_data_length': 6.43, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 9661 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 8, 'name': 'RDB$INDEX_42', 'nodes': 82, 'total_dup': 43}, 9662 {'avg_data_length': 0.6, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9663 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 54, 'name': 'RDB$INDEX_43', 'nodes': 82, 'total_dup': 54}, 9664 {'avg_data_length': 20.92, 'depth': 2, 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=1, d100=2), 9665 'index_id': 2, 'leaf_buckets': 4, 'max_dup': 0, 'name': 'RDB$INDEX_15', 'nodes': 466, 'total_dup': 0}, 9666 {'avg_data_length': 2.33, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=1, d100=0), 9667 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 31, 'name': 'RDB$INDEX_3', 'nodes': 466, 'total_dup': 255}, 9668 {'avg_data_length': 1.1, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 9669 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 27, 'name': 'RDB$INDEX_4', 'nodes': 466, 'total_dup': 408}, 9670 {'avg_data_length': 9.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9671 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_39', 'nodes': 2, 'total_dup': 0}, 9672 {'avg_data_length': 1.06, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9673 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_7', 'nodes': 182, 'total_dup': 0}, 9674 {'avg_data_length': 0.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9675 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_32', 'nodes': 0, 'total_dup': 0}, 9676 {'avg_data_length': 2.84, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9677 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 18, 'name': 'RDB$INDEX_38', 'nodes': 69, 'total_dup': 48}, 9678 {'avg_data_length': 2.09, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9679 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_8', 'nodes': 69, 'total_dup': 0}, 9680 {'avg_data_length': 1.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9681 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 5, 'name': 'RDB$INDEX_35', 'nodes': 36, 'total_dup': 12}, 9682 {'avg_data_length': 4.22, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 9683 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 1, 'name': 'RDB$INDEX_37', 'nodes': 228, 'total_dup': 16}, 9684 {'avg_data_length': 1.24, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9685 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 9, 'name': 'RDB$INDEX_29', 'nodes': 173, 'total_dup': 144}, 9686 {'avg_data_length': 0.07, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9687 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 104, 'name': 'RDB$INDEX_30', 'nodes': 173, 'total_dup': 171}, 9688 {'avg_data_length': 5.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9689 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 1, 'name': 'RDB$INDEX_33', 'nodes': 2, 'total_dup': 1}, 9690 {'avg_data_length': 9.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9691 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$INDEX_34', 'nodes': 2, 'total_dup': 0}, 9692 {'avg_data_length': 0.31, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9693 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 21, 'name': 'CHANGEX', 'nodes': 49, 'total_dup': 46}, 9694 {'avg_data_length': 0.9, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9695 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 2, 'name': 'RDB$FOREIGN21', 'nodes': 49, 'total_dup': 16}, 9696 {'avg_data_length': 18.29, 'depth': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 9697 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY20', 'nodes': 49, 'total_dup': 0}, 9698 {'avg_data_length': 0.29, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9699 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 28, 'name': 'UPDATERX', 'nodes': 49, 'total_dup': 46}, 9700 {'avg_data_length': 2.55, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9701 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 6, 'name': 'NEEDX', 'nodes': 33, 'total_dup': 11}, 9702 {'avg_data_length': 1.85, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9703 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 3, 'name': 'QTYX', 'nodes': 33, 'total_dup': 11}, 9704 {'avg_data_length': 0.52, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9705 'index_id': 4, 'leaf_buckets': 1, 'max_dup': 4, 'name': 'RDB$FOREIGN25', 'nodes': 33, 'total_dup': 18}, 9706 {'avg_data_length': 0.45, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9707 'index_id': 5, 'leaf_buckets': 1, 'max_dup': 7, 'name': 'RDB$FOREIGN26', 'nodes': 33, 'total_dup': 25}, 9708 {'avg_data_length': 4.48, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9709 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY24', 'nodes': 33, 'total_dup': 0}, 9710 {'avg_data_length': 0.97, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9711 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 14, 'name': 'SALESTATX', 'nodes': 33, 'total_dup': 27}, 9712 {'avg_data_length': 0.0, 'depth': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9713 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 'name': 'RDB$PRIMARY104', 'nodes': 0, 'total_dup': 0}] 9714 i = 0 9715 while i < len(db.tables): 9716 self.assertDictEqual(data[i], get_object_data(db.indices[i], ['table']), 'Unexpected output from parser (indices)') 9717 i += 1 9718 def test_parse30_h(self): 9719 db = self._parse_file(os.path.join(self.dbpath, 'gstat30-h.out')) 9720 data = {'attributes': (0,), 'backup_diff_file': None, 'backup_guid': '{F978F787-7023-4C4A-F79D-8D86645B0487}', 9721 'bumped_transaction': None, 'checksum': 12345, 'completed': datetime.datetime(2018, 4, 4, 15, 41, 34), 9722 'continuation_file': None, 'continuation_files': 0, 'creation_date': datetime.datetime(2015, 11, 27, 11, 19, 39), 9723 'database_dialect': 3, 'encrypted_blob_pages': None, 'encrypted_data_pages': None, 'encrypted_index_pages': None, 9724 'executed': datetime.datetime(2018, 4, 4, 15, 41, 34), 'filename': '/home/fdb/test/FBTEST30.FDB', 'flags': 0, 9725 'generation': 2176, 'gstat_version': 3, 'implementation': 'HW=AMD/Intel/x64 little-endian OS=Linux CC=gcc', 9726 'implementation_id': 0, 'indices': 0, 'last_logical_page': None, 'next_attachment_id': 1199, 'next_header_page': 0, 9727 'next_transaction': 2141, 'oat': 2140, 'ods_version': '12.0', 'oit': 179, 'ost': 2140, 'page_buffers': 0, 9728 'page_size': 8192, 'replay_logging_file': None, 'root_filename': None, 'sequence_number': 0, 'shadow_count': 0, 9729 'sweep_interval': None, 'system_change_number': 24, 'tables': 0} 9730 self.assertIsInstance(db, gstat.StatDatabase) 9731 self.assertDictEqual(data, get_object_data(db), 'Unexpected output from parser (database hdr)') 9732 # 9733 self.assertFalse(db.has_table_stats()) 9734 self.assertFalse(db.has_index_stats()) 9735 self.assertFalse(db.has_row_stats()) 9736 self.assertFalse(db.has_encryption_stats()) 9737 self.assertFalse(db.has_system()) 9738 def test_parse30_a(self): 9739 db = self._parse_file(os.path.join(self.dbpath, 'gstat30-a.out')) 9740 # Database 9741 data = {'attributes': (0,), 'backup_diff_file': None, 'backup_guid': '{F978F787-7023-4C4A-F79D-8D86645B0487}', 9742 'bumped_transaction': None, 'checksum': 12345, 'completed': datetime.datetime(2018, 4, 4, 15, 42), 9743 'continuation_file': None, 'continuation_files': 0, 'creation_date': datetime.datetime(2015, 11, 27, 11, 19, 39), 9744 'database_dialect': 3, 'encrypted_blob_pages': None, 'encrypted_data_pages': None, 'encrypted_index_pages': None, 9745 'executed': datetime.datetime(2018, 4, 4, 15, 42), 'filename': '/home/fdb/test/FBTEST30.FDB', 'flags': 0, 9746 'generation': 2176, 'gstat_version': 3, 'implementation': 'HW=AMD/Intel/x64 little-endian OS=Linux CC=gcc', 9747 'implementation_id': 0, 'indices': 39, 'last_logical_page': None, 'next_attachment_id': 1199, 'next_header_page': 0, 9748 'next_transaction': 2141, 'oat': 2140, 'ods_version': '12.0', 'oit': 179, 'ost': 2140, 'page_buffers': 0, 9749 'page_size': 8192, 'replay_logging_file': None, 'root_filename': None, 'sequence_number': 0, 'shadow_count': 0, 9750 'sweep_interval': None, 'system_change_number': 24, 'tables': 16} 9751 self.assertDictEqual(data, get_object_data(db), 'Unexpected output from parser (database hdr)') 9752 # 9753 self.assertTrue(db.has_table_stats()) 9754 self.assertTrue(db.has_index_stats()) 9755 self.assertFalse(db.has_row_stats()) 9756 self.assertFalse(db.has_encryption_stats()) 9757 self.assertFalse(db.has_system()) 9758 # Tables 9759 data = [{'avg_fill': 86, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9760 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9761 'data_page_slots': 3, 'data_pages': 3, 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=1, d100=2), 9762 'empty_pages': 0, 'full_pages': 1, 'index_root_page': 299, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 9763 'max_fragments': None, 'max_versions': None, 'name': 'AR', 'pointer_pages': 1, 'primary_pages': 1, 9764 'primary_pointer_page': 297, 'secondary_pages': 2, 'swept_pages': 0, 'table_id': 140, 'total_formats': None, 9765 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9766 {'avg_fill': 8, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9767 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9768 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9769 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 183, 'indices': 1, 'level_0': None, 'level_1': None, 'level_2': None, 9770 'max_fragments': None, 'max_versions': None, 'name': 'COUNTRY', 'pointer_pages': 1, 'primary_pages': 1, 9771 'primary_pointer_page': 182, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 128, 'total_formats': None, 9772 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9773 {'avg_fill': 26, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9774 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9775 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 9776 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 262, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 9777 'max_fragments': None, 'max_versions': None, 'name': 'CUSTOMER', 'pointer_pages': 1, 'primary_pages': 1, 9778 'primary_pointer_page': 261, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 137, 'total_formats': None, 9779 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9780 {'avg_fill': 24, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9781 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9782 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 9783 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 199, 'indices': 5, 'level_0': None, 'level_1': None, 'level_2': None, 9784 'max_fragments': None, 'max_versions': None, 'name': 'DEPARTMENT', 'pointer_pages': 1, 'primary_pages': 1, 9785 'primary_pointer_page': 198, 'secondary_pages': 0, 'swept_pages': 1, 'table_id': 130, 'total_formats': None, 9786 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9787 {'avg_fill': 44, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9788 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9789 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 9790 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 213, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 9791 'max_fragments': None, 'max_versions': None, 'name': 'EMPLOYEE', 'pointer_pages': 1, 'primary_pages': 1, 9792 'primary_pointer_page': 212, 'secondary_pages': 0, 'swept_pages': 1, 'table_id': 131, 'total_formats': None, 9793 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9794 {'avg_fill': 10, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9795 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9796 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9797 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 235, 'indices': 3, 'level_0': None, 'level_1': None, 'level_2': None, 9798 'max_fragments': None, 'max_versions': None, 'name': 'EMPLOYEE_PROJECT', 'pointer_pages': 1, 'primary_pages': 1, 9799 'primary_pointer_page': 234, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 134, 'total_formats': None, 9800 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9801 {'avg_fill': 54, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9802 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9803 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=1, d100=0), 9804 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 190, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 9805 'max_fragments': None, 'max_versions': None, 'name': 'JOB', 'pointer_pages': 1, 'primary_pages': 1, 9806 'primary_pointer_page': 189, 'secondary_pages': 1, 'swept_pages': 1, 'table_id': 129, 'total_formats': None, 9807 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9808 {'avg_fill': 7, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9809 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9810 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=2, d40=0, d50=0, d80=0, d100=0), 9811 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 221, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 9812 'max_fragments': None, 'max_versions': None, 'name': 'PROJECT', 'pointer_pages': 1, 'primary_pages': 1, 9813 'primary_pointer_page': 220, 'secondary_pages': 1, 'swept_pages': 1, 'table_id': 133, 'total_formats': None, 9814 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9815 {'avg_fill': 20, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9816 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9817 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=1, d40=1, d50=0, d80=0, d100=0), 9818 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 248, 'indices': 3, 'level_0': None, 'level_1': None, 'level_2': None, 9819 'max_fragments': None, 'max_versions': None, 'name': 'PROJ_DEPT_BUDGET', 'pointer_pages': 1, 'primary_pages': 1, 9820 'primary_pointer_page': 239, 'secondary_pages': 1, 'swept_pages': 0, 'table_id': 135, 'total_formats': None, 9821 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9822 {'avg_fill': 30, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9823 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9824 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 9825 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 254, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 9826 'max_fragments': None, 'max_versions': None, 'name': 'SALARY_HISTORY', 'pointer_pages': 1, 'primary_pages': 1, 9827 'primary_pointer_page': 253, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 136, 'total_formats': None, 9828 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9829 {'avg_fill': 35, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9830 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9831 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 9832 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 268, 'indices': 6, 'level_0': None, 'level_1': None, 'level_2': None, 9833 'max_fragments': None, 'max_versions': None, 'name': 'SALES', 'pointer_pages': 1, 'primary_pages': 1, 9834 'primary_pointer_page': 267, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 138, 'total_formats': None, 9835 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9836 {'avg_fill': 0, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9837 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9838 'data_page_slots': 0, 'data_pages': 0, 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 9839 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 324, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 9840 'max_fragments': None, 'max_versions': None, 'name': 'T', 'pointer_pages': 1, 'primary_pages': 0, 9841 'primary_pointer_page': 323, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 147, 'total_formats': None, 9842 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9843 {'avg_fill': 8, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9844 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9845 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=2, d40=0, d50=0, d80=0, d100=0), 9846 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 303, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 9847 'max_fragments': None, 'max_versions': None, 'name': 'T2', 'pointer_pages': 1, 'primary_pages': 1, 9848 'primary_pointer_page': 302, 'secondary_pages': 1, 'swept_pages': 0, 'table_id': 142, 'total_formats': None, 9849 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9850 {'avg_fill': 3, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9851 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9852 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=2, d40=0, d50=0, d80=0, d100=0), 9853 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 306, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 9854 'max_fragments': None, 'max_versions': None, 'name': 'T3', 'pointer_pages': 1, 'primary_pages': 1, 9855 'primary_pointer_page': 305, 'secondary_pages': 1, 'swept_pages': 0, 'table_id': 143, 'total_formats': None, 9856 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9857 {'avg_fill': 3, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9858 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9859 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 9860 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 308, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 9861 'max_fragments': None, 'max_versions': None, 'name': 'T4', 'pointer_pages': 1, 'primary_pages': 1, 9862 'primary_pointer_page': 307, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 144, 'total_formats': None, 9863 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 9864 {'avg_fill': 0, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 9865 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 9866 'data_page_slots': 0, 'data_pages': 0, 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 9867 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 316, 'indices': 1, 'level_0': None, 'level_1': None, 'level_2': None, 9868 'max_fragments': None, 'max_versions': None, 'name': 'T5', 'pointer_pages': 1, 'primary_pages': 0, 9869 'primary_pointer_page': 315, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 145, 'total_formats': None, 9870 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}] 9871 i = 0 9872 while i < len(db.tables): 9873 self.assertDictEqual(data[i], get_object_data(db.tables[i]), 'Unexpected output from parser (tables)') 9874 i += 1 9875 # Indices 9876 data = [{'avg_data_length': 6.44, 'avg_key_length': 8.63, 'avg_node_length': 10.44, 'avg_prefix_length': 0.44, 9877 'clustering_factor': 1.0, 'compression_ratio': 0.8, 'depth': 1, 9878 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 9879 'name': 'RDB$PRIMARY1', 'nodes': 16, 'ratio': 0.06, 'root_page': 186, 'total_dup': 0}, 9880 {'avg_data_length': 15.87, 'avg_key_length': 18.27, 'avg_node_length': 19.87, 'avg_prefix_length': 0.6, 9881 'clustering_factor': 1.0, 'compression_ratio': 0.9, 'depth': 1, 9882 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 0, 9883 'name': 'CUSTNAMEX', 'nodes': 15, 'ratio': 0.07, 'root_page': 276, 'total_dup': 0}, 9884 {'avg_data_length': 17.27, 'avg_key_length': 20.2, 'avg_node_length': 21.27, 'avg_prefix_length': 2.33, 9885 'clustering_factor': 1.0, 'compression_ratio': 0.97, 'depth': 1, 9886 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 0, 9887 'name': 'CUSTREGION', 'nodes': 15, 'ratio': 0.07, 'root_page': 283, 'total_dup': 0}, 9888 {'avg_data_length': 4.87, 'avg_key_length': 6.93, 'avg_node_length': 8.6, 'avg_prefix_length': 0.87, 9889 'clustering_factor': 1.0, 'compression_ratio': 0.83, 'depth': 1, 9890 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 4, 9891 'name': 'RDB$FOREIGN23', 'nodes': 15, 'ratio': 0.07, 'root_page': 264, 'total_dup': 4}, 9892 {'avg_data_length': 1.13, 'avg_key_length': 3.13, 'avg_node_length': 4.2, 'avg_prefix_length': 1.87, 9893 'clustering_factor': 1.0, 'compression_ratio': 0.96, 'depth': 1, 9894 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 9895 'name': 'RDB$PRIMARY22', 'nodes': 15, 'ratio': 0.07, 'root_page': 263, 'total_dup': 0}, 9896 {'avg_data_length': 5.38, 'avg_key_length': 8.0, 'avg_node_length': 9.05, 'avg_prefix_length': 3.62, 9897 'clustering_factor': 1.0, 'compression_ratio': 1.13, 'depth': 1, 9898 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 3, 9899 'name': 'BUDGETX', 'nodes': 21, 'ratio': 0.05, 'root_page': 284, 'total_dup': 7}, 9900 {'avg_data_length': 13.95, 'avg_key_length': 16.57, 'avg_node_length': 17.95, 'avg_prefix_length': 5.29, 9901 'clustering_factor': 1.0, 'compression_ratio': 1.16, 'depth': 1, 9902 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 9903 'name': 'RDB$4', 'nodes': 21, 'ratio': 0.05, 'root_page': 208, 'total_dup': 0}, 9904 {'avg_data_length': 1.14, 'avg_key_length': 3.24, 'avg_node_length': 4.29, 'avg_prefix_length': 0.81, 9905 'clustering_factor': 1.0, 'compression_ratio': 0.6, 'depth': 1, 9906 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 'leaf_buckets': 1, 'max_dup': 3, 9907 'name': 'RDB$FOREIGN10', 'nodes': 21, 'ratio': 0.05, 'root_page': 219, 'total_dup': 3}, 9908 {'avg_data_length': 0.81, 'avg_key_length': 2.95, 'avg_node_length': 4.1, 'avg_prefix_length': 2.05, 9909 'clustering_factor': 1.0, 'compression_ratio': 0.97, 'depth': 1, 9910 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 4, 9911 'name': 'RDB$FOREIGN6', 'nodes': 21, 'ratio': 0.05, 'root_page': 210, 'total_dup': 13}, 9912 {'avg_data_length': 1.71, 'avg_key_length': 4.05, 'avg_node_length': 5.24, 'avg_prefix_length': 1.29, 9913 'clustering_factor': 1.0, 'compression_ratio': 0.74, 'depth': 1, 9914 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 9915 'name': 'RDB$PRIMARY5', 'nodes': 21, 'ratio': 0.05, 'root_page': 209, 'total_dup': 0}, 9916 {'avg_data_length': 15.52, 'avg_key_length': 18.5, 'avg_node_length': 19.52, 'avg_prefix_length': 2.17, 9917 'clustering_factor': 1.0, 'compression_ratio': 0.96, 'depth': 1, 9918 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 0, 9919 'name': 'NAMEX', 'nodes': 42, 'ratio': 0.02, 'root_page': 285, 'total_dup': 0}, 9920 {'avg_data_length': 0.81, 'avg_key_length': 2.98, 'avg_node_length': 4.07, 'avg_prefix_length': 2.19, 9921 'clustering_factor': 1.0, 'compression_ratio': 1.01, 'depth': 1, 9922 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 4, 9923 'name': 'RDB$FOREIGN8', 'nodes': 42, 'ratio': 0.02, 'root_page': 215, 'total_dup': 23}, 9924 {'avg_data_length': 6.79, 'avg_key_length': 9.4, 'avg_node_length': 10.43, 'avg_prefix_length': 9.05, 9925 'clustering_factor': 1.0, 'compression_ratio': 1.68, 'depth': 1, 9926 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 4, 9927 'name': 'RDB$FOREIGN9', 'nodes': 42, 'ratio': 0.02, 'root_page': 216, 'total_dup': 15}, 9928 {'avg_data_length': 1.31, 'avg_key_length': 3.6, 'avg_node_length': 4.62, 'avg_prefix_length': 1.17, 9929 'clustering_factor': 1.0, 'compression_ratio': 0.69, 'depth': 1, 9930 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 9931 'name': 'RDB$PRIMARY7', 'nodes': 42, 'ratio': 0.02, 'root_page': 214, 'total_dup': 0}, 9932 {'avg_data_length': 1.04, 'avg_key_length': 3.25, 'avg_node_length': 4.29, 'avg_prefix_length': 1.36, 9933 'clustering_factor': 1.0, 'compression_ratio': 0.74, 'depth': 1, 9934 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 2, 9935 'name': 'RDB$FOREIGN15', 'nodes': 28, 'ratio': 0.04, 'root_page': 237, 'total_dup': 6}, 9936 {'avg_data_length': 0.86, 'avg_key_length': 2.89, 'avg_node_length': 4.04, 'avg_prefix_length': 4.14, 9937 'clustering_factor': 1.0, 'compression_ratio': 1.73, 'depth': 1, 9938 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 9, 9939 'name': 'RDB$FOREIGN16', 'nodes': 28, 'ratio': 0.04, 'root_page': 238, 'total_dup': 23}, 9940 {'avg_data_length': 9.11, 'avg_key_length': 12.07, 'avg_node_length': 13.11, 'avg_prefix_length': 2.89, 9941 'clustering_factor': 1.0, 'compression_ratio': 0.99, 'depth': 1, 9942 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 9943 'name': 'RDB$PRIMARY14', 'nodes': 28, 'ratio': 0.04, 'root_page': 236, 'total_dup': 0}, 9944 {'avg_data_length': 10.9, 'avg_key_length': 13.71, 'avg_node_length': 14.74, 'avg_prefix_length': 7.87, 9945 'clustering_factor': 1.0, 'compression_ratio': 1.37, 'depth': 1, 9946 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 1, 9947 'name': 'MAXSALX', 'nodes': 31, 'ratio': 0.03, 'root_page': 286, 'total_dup': 5}, 9948 {'avg_data_length': 10.29, 'avg_key_length': 13.03, 'avg_node_length': 14.06, 'avg_prefix_length': 8.48, 9949 'clustering_factor': 1.0, 'compression_ratio': 1.44, 'depth': 1, 9950 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 2, 9951 'name': 'MINSALX', 'nodes': 31, 'ratio': 0.03, 'root_page': 287, 'total_dup': 7}, 9952 {'avg_data_length': 1.39, 'avg_key_length': 3.39, 'avg_node_length': 4.61, 'avg_prefix_length': 2.77, 9953 'clustering_factor': 1.0, 'compression_ratio': 1.23, 'depth': 1, 9954 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 20, 9955 'name': 'RDB$FOREIGN3', 'nodes': 31, 'ratio': 0.03, 'root_page': 192, 'total_dup': 24}, 9956 {'avg_data_length': 10.45, 'avg_key_length': 13.42, 'avg_node_length': 14.45, 'avg_prefix_length': 6.19, 9957 'clustering_factor': 1.0, 'compression_ratio': 1.24, 'depth': 1, 9958 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 9959 'name': 'RDB$PRIMARY2', 'nodes': 31, 'ratio': 0.03, 'root_page': 191, 'total_dup': 0}, 9960 {'avg_data_length': 22.5, 'avg_key_length': 25.33, 'avg_node_length': 26.5, 'avg_prefix_length': 4.17, 9961 'clustering_factor': 1.0, 'compression_ratio': 1.05, 'depth': 1, 9962 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 0, 9963 'name': 'PRODTYPEX', 'nodes': 6, 'ratio': 0.17, 'root_page': 288, 'total_dup': 0}, 9964 {'avg_data_length': 13.33, 'avg_key_length': 15.5, 'avg_node_length': 17.33, 'avg_prefix_length': 0.33, 9965 'clustering_factor': 1.0, 'compression_ratio': 0.88, 'depth': 1, 9966 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 9967 'name': 'RDB$11', 'nodes': 6, 'ratio': 0.17, 'root_page': 222, 'total_dup': 0}, 9968 {'avg_data_length': 1.33, 'avg_key_length': 3.5, 'avg_node_length': 4.67, 'avg_prefix_length': 0.67, 9969 'clustering_factor': 1.0, 'compression_ratio': 0.57, 'depth': 1, 9970 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 0, 9971 'name': 'RDB$FOREIGN13', 'nodes': 6, 'ratio': 0.17, 'root_page': 232, 'total_dup': 0}, 9972 {'avg_data_length': 4.83, 'avg_key_length': 7.0, 'avg_node_length': 8.83, 'avg_prefix_length': 0.17, 9973 'clustering_factor': 1.0, 'compression_ratio': 0.71, 'depth': 1, 9974 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 9975 'name': 'RDB$PRIMARY12', 'nodes': 6, 'ratio': 0.17, 'root_page': 223, 'total_dup': 0}, 9976 {'avg_data_length': 0.71, 'avg_key_length': 2.79, 'avg_node_length': 3.92, 'avg_prefix_length': 2.29, 9977 'clustering_factor': 1.0, 'compression_ratio': 1.07, 'depth': 1, 9978 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 5, 9979 'name': 'RDB$FOREIGN18', 'nodes': 24, 'ratio': 0.04, 'root_page': 250, 'total_dup': 15}, 9980 {'avg_data_length': 1.0, 'avg_key_length': 3.04, 'avg_node_length': 4.21, 'avg_prefix_length': 4.0, 9981 'clustering_factor': 1.0, 'compression_ratio': 1.64, 'depth': 1, 9982 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 8, 9983 'name': 'RDB$FOREIGN19', 'nodes': 24, 'ratio': 0.04, 'root_page': 251, 'total_dup': 19}, 9984 {'avg_data_length': 6.83, 'avg_key_length': 9.67, 'avg_node_length': 10.71, 'avg_prefix_length': 12.17, 9985 'clustering_factor': 1.0, 'compression_ratio': 1.97, 'depth': 1, 9986 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 9987 'name': 'RDB$PRIMARY17', 'nodes': 24, 'ratio': 0.04, 'root_page': 249, 'total_dup': 0}, 9988 {'avg_data_length': 0.31, 'avg_key_length': 2.35, 'avg_node_length': 3.37, 'avg_prefix_length': 6.69, 9989 'clustering_factor': 1.0, 'compression_ratio': 2.98, 'depth': 1, 9990 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 21, 9991 'name': 'CHANGEX', 'nodes': 49, 'ratio': 0.02, 'root_page': 289, 'total_dup': 46}, 9992 {'avg_data_length': 0.9, 'avg_key_length': 3.1, 'avg_node_length': 4.12, 'avg_prefix_length': 1.43, 9993 'clustering_factor': 1.0, 'compression_ratio': 0.75, 'depth': 1, 9994 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 2, 9995 'name': 'RDB$FOREIGN21', 'nodes': 49, 'ratio': 0.02, 'root_page': 256, 'total_dup': 16}, 9996 {'avg_data_length': 18.29, 'avg_key_length': 21.27, 'avg_node_length': 22.29, 'avg_prefix_length': 4.31, 9997 'clustering_factor': 1.0, 'compression_ratio': 1.06, 'depth': 1, 9998 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 9999 'name': 'RDB$PRIMARY20', 'nodes': 49, 'ratio': 0.02, 'root_page': 255, 'total_dup': 0}, 10000 {'avg_data_length': 0.29, 'avg_key_length': 2.29, 'avg_node_length': 3.35, 'avg_prefix_length': 5.39, 10001 'clustering_factor': 1.0, 'compression_ratio': 2.48, 'depth': 1, 10002 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 28, 10003 'name': 'UPDATERX', 'nodes': 49, 'ratio': 0.02, 'root_page': 290, 'total_dup': 46}, 10004 {'avg_data_length': 2.55, 'avg_key_length': 4.94, 'avg_node_length': 5.97, 'avg_prefix_length': 2.88, 10005 'clustering_factor': 1.0, 'compression_ratio': 1.1, 'depth': 1, 10006 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 6, 10007 'name': 'NEEDX', 'nodes': 33, 'ratio': 0.03, 'root_page': 291, 'total_dup': 11}, 10008 {'avg_data_length': 1.85, 'avg_key_length': 4.03, 'avg_node_length': 5.06, 'avg_prefix_length': 11.18, 10009 'clustering_factor': 1.0, 'compression_ratio': 3.23, 'depth': 1, 10010 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 'leaf_buckets': 1, 'max_dup': 3, 10011 'name': 'QTYX', 'nodes': 33, 'ratio': 0.03, 'root_page': 292, 'total_dup': 11}, 10012 {'avg_data_length': 0.52, 'avg_key_length': 2.52, 'avg_node_length': 3.55, 'avg_prefix_length': 2.48, 10013 'clustering_factor': 1.0, 'compression_ratio': 1.19, 'depth': 1, 10014 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 4, 10015 'name': 'RDB$FOREIGN25', 'nodes': 33, 'ratio': 0.03, 'root_page': 270, 'total_dup': 18}, 10016 {'avg_data_length': 0.45, 'avg_key_length': 2.64, 'avg_node_length': 3.67, 'avg_prefix_length': 2.21, 10017 'clustering_factor': 1.0, 'compression_ratio': 1.01, 'depth': 1, 10018 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 7, 10019 'name': 'RDB$FOREIGN26', 'nodes': 33, 'ratio': 0.03, 'root_page': 271, 'total_dup': 25}, 10020 {'avg_data_length': 4.48, 'avg_key_length': 7.42, 'avg_node_length': 8.45, 'avg_prefix_length': 3.52, 10021 'clustering_factor': 1.0, 'compression_ratio': 1.08, 'depth': 1, 10022 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10023 'name': 'RDB$PRIMARY24', 'nodes': 33, 'ratio': 0.03, 'root_page': 269, 'total_dup': 0}, 10024 {'avg_data_length': 0.97, 'avg_key_length': 3.03, 'avg_node_length': 4.06, 'avg_prefix_length': 9.82, 10025 'clustering_factor': 1.0, 'compression_ratio': 3.56, 'depth': 1, 10026 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 5, 'leaf_buckets': 1, 'max_dup': 14, 10027 'name': 'SALESTATX', 'nodes': 33, 'ratio': 0.03, 'root_page': 293, 'total_dup': 27}, 10028 {'avg_data_length': 0.0, 'avg_key_length': 0.0, 'avg_node_length': 0.0, 'avg_prefix_length': 0.0, 10029 'clustering_factor': 0.0, 'compression_ratio': 0.0, 'depth': 1, 10030 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10031 'name': 'RDB$PRIMARY28', 'nodes': 0, 'ratio': 0.0, 'root_page': 317, 'total_dup': 0}] 10032 i = 0 10033 while i < len(db.tables): 10034 self.assertDictEqual(data[i], get_object_data(db.indices[i], ['table']), 'Unexpected output from parser (indices)') 10035 i += 1 10036 def test_parse30_d(self): 10037 db = self._parse_file(os.path.join(self.dbpath, 'gstat30-d.out')) 10038 # 10039 self.assertTrue(db.has_table_stats()) 10040 self.assertFalse(db.has_index_stats()) 10041 self.assertFalse(db.has_row_stats()) 10042 self.assertFalse(db.has_encryption_stats()) 10043 self.assertFalse(db.has_system()) 10044 # Tables 10045 data = [{'avg_fill': 86, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10046 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10047 'data_page_slots': 3, 'data_pages': 3, 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=1, d100=2), 10048 'empty_pages': 0, 'full_pages': 1, 'index_root_page': 299, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10049 'max_fragments': None, 'max_versions': None, 'name': 'AR', 'pointer_pages': 1, 'primary_pages': 1, 10050 'primary_pointer_page': 297, 'secondary_pages': 2, 'swept_pages': 0, 'table_id': 140, 'total_formats': None, 10051 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10052 {'avg_fill': 8, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10053 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10054 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 10055 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 183, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10056 'max_fragments': None, 'max_versions': None, 'name': 'COUNTRY', 'pointer_pages': 1, 'primary_pages': 1, 10057 'primary_pointer_page': 182, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 128, 'total_formats': None, 10058 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10059 {'avg_fill': 26, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10060 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10061 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 10062 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 262, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10063 'max_fragments': None, 'max_versions': None, 'name': 'CUSTOMER', 'pointer_pages': 1, 'primary_pages': 1, 10064 'primary_pointer_page': 261, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 137, 'total_formats': None, 10065 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10066 {'avg_fill': 24, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10067 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10068 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 10069 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 199, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10070 'max_fragments': None, 'max_versions': None, 'name': 'DEPARTMENT', 'pointer_pages': 1, 'primary_pages': 1, 10071 'primary_pointer_page': 198, 'secondary_pages': 0, 'swept_pages': 1, 'table_id': 130, 'total_formats': None, 10072 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10073 {'avg_fill': 44, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10074 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10075 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 10076 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 213, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10077 'max_fragments': None, 'max_versions': None, 'name': 'EMPLOYEE', 'pointer_pages': 1, 'primary_pages': 1, 10078 'primary_pointer_page': 212, 'secondary_pages': 0, 'swept_pages': 1, 'table_id': 131, 'total_formats': None, 10079 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10080 {'avg_fill': 10, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10081 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10082 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 10083 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 235, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10084 'max_fragments': None, 'max_versions': None, 'name': 'EMPLOYEE_PROJECT', 'pointer_pages': 1, 'primary_pages': 1, 10085 'primary_pointer_page': 234, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 134, 'total_formats': None, 10086 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10087 {'avg_fill': 54, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10088 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10089 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=1, d100=0), 10090 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 190, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10091 'max_fragments': None, 'max_versions': None, 'name': 'JOB', 'pointer_pages': 1, 'primary_pages': 1, 10092 'primary_pointer_page': 189, 'secondary_pages': 1, 'swept_pages': 1, 'table_id': 129, 'total_formats': None, 10093 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10094 {'avg_fill': 7, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10095 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10096 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=2, d40=0, d50=0, d80=0, d100=0), 10097 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 221, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10098 'max_fragments': None, 'max_versions': None, 'name': 'PROJECT', 'pointer_pages': 1, 'primary_pages': 1, 10099 'primary_pointer_page': 220, 'secondary_pages': 1, 'swept_pages': 1, 'table_id': 133, 'total_formats': None, 10100 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10101 {'avg_fill': 20, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10102 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10103 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=1, d40=1, d50=0, d80=0, d100=0), 10104 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 248, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10105 'max_fragments': None, 'max_versions': None, 'name': 'PROJ_DEPT_BUDGET', 'pointer_pages': 1, 'primary_pages': 1, 10106 'primary_pointer_page': 239, 'secondary_pages': 1, 'swept_pages': 0, 'table_id': 135, 'total_formats': None, 10107 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10108 {'avg_fill': 30, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10109 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10110 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 10111 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 254, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10112 'max_fragments': None, 'max_versions': None, 'name': 'SALARY_HISTORY', 'pointer_pages': 1, 'primary_pages': 1, 10113 'primary_pointer_page': 253, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 136, 'total_formats': None, 10114 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10115 {'avg_fill': 35, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10116 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10117 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 10118 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 268, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10119 'max_fragments': None, 'max_versions': None, 'name': 'SALES', 'pointer_pages': 1, 'primary_pages': 1, 10120 'primary_pointer_page': 267, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 138, 'total_formats': None, 10121 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10122 {'avg_fill': 0, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10123 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10124 'data_page_slots': 0, 'data_pages': 0, 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 10125 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 324, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10126 'max_fragments': None, 'max_versions': None, 'name': 'T', 'pointer_pages': 1, 'primary_pages': 0, 10127 'primary_pointer_page': 323, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 147, 'total_formats': None, 10128 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10129 {'avg_fill': 8, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10130 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10131 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=2, d40=0, d50=0, d80=0, d100=0), 10132 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 303, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10133 'max_fragments': None, 'max_versions': None, 'name': 'T2', 'pointer_pages': 1, 'primary_pages': 1, 10134 'primary_pointer_page': 302, 'secondary_pages': 1, 'swept_pages': 0, 'table_id': 142, 'total_formats': None, 10135 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10136 {'avg_fill': 3, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10137 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10138 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=2, d40=0, d50=0, d80=0, d100=0), 10139 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 306, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10140 'max_fragments': None, 'max_versions': None, 'name': 'T3', 'pointer_pages': 1, 'primary_pages': 1, 10141 'primary_pointer_page': 305, 'secondary_pages': 1, 'swept_pages': 0, 'table_id': 143, 'total_formats': None, 10142 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10143 {'avg_fill': 3, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10144 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10145 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 10146 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 308, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10147 'max_fragments': None, 'max_versions': None, 'name': 'T4', 'pointer_pages': 1, 'primary_pages': 1, 10148 'primary_pointer_page': 307, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 144, 'total_formats': None, 10149 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10150 {'avg_fill': 0, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10151 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10152 'data_page_slots': 0, 'data_pages': 0, 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 10153 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 316, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10154 'max_fragments': None, 'max_versions': None, 'name': 'T5', 'pointer_pages': 1, 'primary_pages': 0, 10155 'primary_pointer_page': 315, 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 145, 'total_formats': None, 10156 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}] 10157 i = 0 10158 while i < len(db.tables): 10159 self.assertDictEqual(data[i], get_object_data(db.tables[i]), 'Unexpected output from parser (tables)') 10160 i += 1 10161 # Indices 10162 self.assertEqual(len(db.indices), 0) 10163 def test_parse30_e(self): 10164 db = self._parse_file(os.path.join(self.dbpath, 'gstat30-e.out')) 10165 data = {'attributes': (0,), 'backup_diff_file': None, 'backup_guid': '{F978F787-7023-4C4A-F79D-8D86645B0487}', 10166 'bumped_transaction': None, 'checksum': 12345, 'completed': datetime.datetime(2018, 4, 4, 15, 45, 6), 10167 'continuation_file': None, 'continuation_files': 0, 'creation_date': datetime.datetime(2015, 11, 27, 11, 19, 39), 10168 'database_dialect': 3, 'encrypted_blob_pages': Encryption(pages=11, encrypted=0, unencrypted=11), 10169 'encrypted_data_pages': Encryption(pages=121, encrypted=0, unencrypted=121), 10170 'encrypted_index_pages': Encryption(pages=96, encrypted=0, unencrypted=96), 10171 'executed': datetime.datetime(2018, 4, 4, 15, 45, 6), 'filename': '/home/fdb/test/FBTEST30.FDB', 'flags': 0, 10172 'generation': 2181, 'gstat_version': 3, 'implementation': 'HW=AMD/Intel/x64 little-endian OS=Linux CC=gcc', 10173 'implementation_id': 0, 'indices': 0, 'last_logical_page': None, 'next_attachment_id': 1214, 10174 'next_header_page': 0, 'next_transaction': 2146, 'oat': 2146, 'ods_version': '12.0', 'oit': 179, 'ost': 2146, 10175 'page_buffers': 0, 'page_size': 8192, 'replay_logging_file': None, 'root_filename': None, 'sequence_number': 0, 10176 'shadow_count': 0, 'sweep_interval': None, 'system_change_number': 24, 'tables': 0} 10177 self.assertIsInstance(db, gstat.StatDatabase) 10178 self.assertDictEqual(data, get_object_data(db), 'Unexpected output from parser (database hdr)') 10179 # 10180 self.assertFalse(db.has_table_stats()) 10181 self.assertFalse(db.has_index_stats()) 10182 self.assertFalse(db.has_row_stats()) 10183 self.assertTrue(db.has_encryption_stats()) 10184 self.assertFalse(db.has_system()) 10185 def test_parse30_f(self): 10186 db = self._parse_file(os.path.join(self.dbpath, 'gstat30-f.out')) 10187 # 10188 self.assertTrue(db.has_table_stats()) 10189 self.assertTrue(db.has_index_stats()) 10190 self.assertTrue(db.has_row_stats()) 10191 self.assertFalse(db.has_encryption_stats()) 10192 self.assertTrue(db.has_system()) 10193 def test_parse30_i(self): 10194 db = self._parse_file(os.path.join(self.dbpath, 'gstat30-i.out')) 10195 # 10196 self.assertFalse(db.has_table_stats()) 10197 self.assertTrue(db.has_index_stats()) 10198 self.assertFalse(db.has_row_stats()) 10199 self.assertFalse(db.has_encryption_stats()) 10200 # Tables 10201 data = [{'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10202 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10203 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10204 'index_root_page': None, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10205 'max_versions': None, 'name': 'AR', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10206 'secondary_pages': None, 'swept_pages': None, 'table_id': 140, 'total_formats': None, 'total_fragments': None, 10207 'total_records': None, 'total_versions': None, 'used_formats': None}, 10208 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10209 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10210 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10211 'index_root_page': None, 'indices': 1, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10212 'max_versions': None, 'name': 'COUNTRY', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10213 'secondary_pages': None, 'swept_pages': None, 'table_id': 128, 'total_formats': None, 'total_fragments': None, 10214 'total_records': None, 'total_versions': None, 'used_formats': None}, 10215 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10216 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10217 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10218 'index_root_page': None, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10219 'max_versions': None, 'name': 'CUSTOMER', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10220 'secondary_pages': None, 'swept_pages': None, 'table_id': 137, 'total_formats': None, 'total_fragments': None, 10221 'total_records': None, 'total_versions': None, 'used_formats': None}, 10222 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10223 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10224 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10225 'index_root_page': None, 'indices': 5, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10226 'max_versions': None, 'name': 'DEPARTMENT', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10227 'secondary_pages': None, 'swept_pages': None, 'table_id': 130, 'total_formats': None, 'total_fragments': None, 10228 'total_records': None, 'total_versions': None, 'used_formats': None}, 10229 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10230 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10231 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10232 'index_root_page': None, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10233 'max_versions': None, 'name': 'EMPLOYEE', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10234 'secondary_pages': None, 'swept_pages': None, 'table_id': 131, 'total_formats': None, 'total_fragments': None, 10235 'total_records': None, 'total_versions': None, 'used_formats': None}, 10236 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10237 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10238 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10239 'index_root_page': None, 'indices': 3, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10240 'max_versions': None, 'name': 'EMPLOYEE_PROJECT', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10241 'secondary_pages': None, 'swept_pages': None, 'table_id': 134, 'total_formats': None, 'total_fragments': None, 10242 'total_records': None, 'total_versions': None, 'used_formats': None}, 10243 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10244 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10245 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10246 'index_root_page': None, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10247 'max_versions': None, 'name': 'JOB', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10248 'secondary_pages': None, 'swept_pages': None, 'table_id': 129, 'total_formats': None, 'total_fragments': None, 10249 'total_records': None, 'total_versions': None, 'used_formats': None}, 10250 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10251 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10252 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10253 'index_root_page': None, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10254 'max_versions': None, 'name': 'PROJECT', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10255 'secondary_pages': None, 'swept_pages': None, 'table_id': 133, 'total_formats': None, 'total_fragments': None, 10256 'total_records': None, 'total_versions': None, 'used_formats': None}, 10257 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10258 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10259 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10260 'index_root_page': None, 'indices': 3, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10261 'max_versions': None, 'name': 'PROJ_DEPT_BUDGET', 'pointer_pages': None, 'primary_pages': None, 10262 'primary_pointer_page': None, 'secondary_pages': None, 'swept_pages': None, 'table_id': 135, 'total_formats': None, 10263 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10264 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10265 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10266 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10267 'index_root_page': None, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10268 'max_versions': None, 'name': 'SALARY_HISTORY', 'pointer_pages': None, 'primary_pages': None, 10269 'primary_pointer_page': None, 'secondary_pages': None, 'swept_pages': None, 'table_id': 136, 'total_formats': None, 10270 'total_fragments': None, 'total_records': None, 'total_versions': None, 'used_formats': None}, 10271 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10272 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10273 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10274 'index_root_page': None, 'indices': 6, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10275 'max_versions': None, 'name': 'SALES', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10276 'secondary_pages': None, 'swept_pages': None, 'table_id': 138, 'total_formats': None, 'total_fragments': None, 10277 'total_records': None, 'total_versions': None, 'used_formats': None}, 10278 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10279 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10280 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10281 'index_root_page': None, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10282 'max_versions': None, 'name': 'T', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10283 'secondary_pages': None, 'swept_pages': None, 'table_id': 147, 'total_formats': None, 'total_fragments': None, 10284 'total_records': None, 'total_versions': None, 'used_formats': None}, 10285 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10286 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10287 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10288 'index_root_page': None, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10289 'max_versions': None, 'name': 'T2', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10290 'secondary_pages': None, 'swept_pages': None, 'table_id': 142, 'total_formats': None, 'total_fragments': None, 10291 'total_records': None, 'total_versions': None, 'used_formats': None}, 10292 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10293 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10294 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10295 'index_root_page': None, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10296 'max_versions': None, 'name': 'T3', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10297 'secondary_pages': None, 'swept_pages': None, 'table_id': 143, 'total_formats': None, 'total_fragments': None, 10298 'total_records': None, 'total_versions': None, 'used_formats': None}, 10299 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10300 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10301 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10302 'index_root_page': None, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10303 'max_versions': None, 'name': 'T4', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10304 'secondary_pages': None, 'swept_pages': None, 'table_id': 144, 'total_formats': None, 'total_fragments': None, 10305 'total_records': None, 'total_versions': None, 'used_formats': None}, 10306 {'avg_fill': None, 'avg_fragment_length': None, 'avg_record_length': None, 'avg_unpacked_length': None, 10307 'avg_version_length': None, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': None, 10308 'data_page_slots': None, 'data_pages': None, 'distribution': None, 'empty_pages': None, 'full_pages': None, 10309 'index_root_page': None, 'indices': 1, 'level_0': None, 'level_1': None, 'level_2': None, 'max_fragments': None, 10310 'max_versions': None, 'name': 'T5', 'pointer_pages': None, 'primary_pages': None, 'primary_pointer_page': None, 10311 'secondary_pages': None, 'swept_pages': None, 'table_id': 145, 'total_formats': None, 'total_fragments': None, 10312 'total_records': None, 'total_versions': None, 'used_formats': None}] 10313 i = 0 10314 while i < len(db.tables): 10315 self.assertDictEqual(data[i], get_object_data(db.tables[i]), 'Unexpected output from parser (tables)') 10316 i += 1 10317 # Indices 10318 data = [{'avg_data_length': 6.44, 'avg_key_length': 8.63, 'avg_node_length': 10.44, 'avg_prefix_length': 0.44, 10319 'clustering_factor': 1.0, 'compression_ratio': 0.8, 'depth': 1, 10320 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10321 'name': 'RDB$PRIMARY1', 'nodes': 16, 'ratio': 0.06, 'root_page': 186, 'total_dup': 0}, 10322 {'avg_data_length': 15.87, 'avg_key_length': 18.27, 'avg_node_length': 19.87, 'avg_prefix_length': 0.6, 10323 'clustering_factor': 1.0, 'compression_ratio': 0.9, 'depth': 1, 10324 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 0, 10325 'name': 'CUSTNAMEX', 'nodes': 15, 'ratio': 0.07, 'root_page': 276, 'total_dup': 0}, 10326 {'avg_data_length': 17.27, 'avg_key_length': 20.2, 'avg_node_length': 21.27, 'avg_prefix_length': 2.33, 10327 'clustering_factor': 1.0, 'compression_ratio': 0.97, 'depth': 1, 10328 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 0, 10329 'name': 'CUSTREGION', 'nodes': 15, 'ratio': 0.07, 'root_page': 283, 'total_dup': 0}, 10330 {'avg_data_length': 4.87, 'avg_key_length': 6.93, 'avg_node_length': 8.6, 'avg_prefix_length': 0.87, 10331 'clustering_factor': 1.0, 'compression_ratio': 0.83, 'depth': 1, 10332 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 4, 10333 'name': 'RDB$FOREIGN23', 'nodes': 15, 'ratio': 0.07, 'root_page': 264, 'total_dup': 4}, 10334 {'avg_data_length': 1.13, 'avg_key_length': 3.13, 'avg_node_length': 4.2, 'avg_prefix_length': 1.87, 10335 'clustering_factor': 1.0, 'compression_ratio': 0.96, 'depth': 1, 10336 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10337 'name': 'RDB$PRIMARY22', 'nodes': 15, 'ratio': 0.07, 'root_page': 263, 'total_dup': 0}, 10338 {'avg_data_length': 5.38, 'avg_key_length': 8.0, 'avg_node_length': 9.05, 'avg_prefix_length': 3.62, 10339 'clustering_factor': 1.0, 'compression_ratio': 1.13, 'depth': 1, 10340 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 3, 10341 'name': 'BUDGETX', 'nodes': 21, 'ratio': 0.05, 'root_page': 284, 'total_dup': 7}, 10342 {'avg_data_length': 13.95, 'avg_key_length': 16.57, 'avg_node_length': 17.95, 'avg_prefix_length': 5.29, 10343 'clustering_factor': 1.0, 'compression_ratio': 1.16, 'depth': 1, 10344 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10345 'name': 'RDB$4', 'nodes': 21, 'ratio': 0.05, 'root_page': 208, 'total_dup': 0}, 10346 {'avg_data_length': 1.14, 'avg_key_length': 3.24, 'avg_node_length': 4.29, 'avg_prefix_length': 0.81, 10347 'clustering_factor': 1.0, 'compression_ratio': 0.6, 'depth': 1, 10348 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 'leaf_buckets': 1, 'max_dup': 3, 10349 'name': 'RDB$FOREIGN10', 'nodes': 21, 'ratio': 0.05, 'root_page': 219, 'total_dup': 3}, 10350 {'avg_data_length': 0.81, 'avg_key_length': 2.95, 'avg_node_length': 4.1, 'avg_prefix_length': 2.05, 10351 'clustering_factor': 1.0, 'compression_ratio': 0.97, 'depth': 1, 10352 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 4, 10353 'name': 'RDB$FOREIGN6', 'nodes': 21, 'ratio': 0.05, 'root_page': 210, 'total_dup': 13}, 10354 {'avg_data_length': 1.71, 'avg_key_length': 4.05, 'avg_node_length': 5.24, 'avg_prefix_length': 1.29, 10355 'clustering_factor': 1.0, 'compression_ratio': 0.74, 'depth': 1, 10356 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 10357 'name': 'RDB$PRIMARY5', 'nodes': 21, 'ratio': 0.05, 'root_page': 209, 'total_dup': 0}, 10358 {'avg_data_length': 15.52, 'avg_key_length': 18.5, 'avg_node_length': 19.52, 'avg_prefix_length': 2.17, 10359 'clustering_factor': 1.0, 'compression_ratio': 0.96, 'depth': 1, 10360 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 0, 10361 'name': 'NAMEX', 'nodes': 42, 'ratio': 0.02, 'root_page': 285, 'total_dup': 0}, 10362 {'avg_data_length': 0.81, 'avg_key_length': 2.98, 'avg_node_length': 4.07, 'avg_prefix_length': 2.19, 10363 'clustering_factor': 1.0, 'compression_ratio': 1.01, 'depth': 1, 10364 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 4, 10365 'name': 'RDB$FOREIGN8', 'nodes': 42, 'ratio': 0.02, 'root_page': 215, 'total_dup': 23}, 10366 {'avg_data_length': 6.79, 'avg_key_length': 9.4, 'avg_node_length': 10.43, 'avg_prefix_length': 9.05, 10367 'clustering_factor': 1.0, 'compression_ratio': 1.68, 'depth': 1, 10368 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 4, 10369 'name': 'RDB$FOREIGN9', 'nodes': 42, 'ratio': 0.02, 'root_page': 216, 'total_dup': 15}, 10370 {'avg_data_length': 1.31, 'avg_key_length': 3.6, 'avg_node_length': 4.62, 'avg_prefix_length': 1.17, 10371 'clustering_factor': 1.0, 'compression_ratio': 0.69, 'depth': 1, 10372 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10373 'name': 'RDB$PRIMARY7', 'nodes': 42, 'ratio': 0.02, 'root_page': 214, 'total_dup': 0}, 10374 {'avg_data_length': 1.04, 'avg_key_length': 3.25, 'avg_node_length': 4.29, 'avg_prefix_length': 1.36, 10375 'clustering_factor': 1.0, 'compression_ratio': 0.74, 'depth': 1, 10376 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 2, 10377 'name': 'RDB$FOREIGN15', 'nodes': 28, 'ratio': 0.04, 'root_page': 237, 'total_dup': 6}, 10378 {'avg_data_length': 0.86, 'avg_key_length': 2.89, 'avg_node_length': 4.04, 'avg_prefix_length': 4.14, 10379 'clustering_factor': 1.0, 'compression_ratio': 1.73, 'depth': 1, 10380 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 9, 10381 'name': 'RDB$FOREIGN16', 'nodes': 28, 'ratio': 0.04, 'root_page': 238, 'total_dup': 23}, 10382 {'avg_data_length': 9.11, 'avg_key_length': 12.07, 'avg_node_length': 13.11, 'avg_prefix_length': 2.89, 10383 'clustering_factor': 1.0, 'compression_ratio': 0.99, 'depth': 1, 10384 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10385 'name': 'RDB$PRIMARY14', 'nodes': 28, 'ratio': 0.04, 'root_page': 236, 'total_dup': 0}, 10386 {'avg_data_length': 10.9, 'avg_key_length': 13.71, 'avg_node_length': 14.74, 'avg_prefix_length': 7.87, 10387 'clustering_factor': 1.0, 'compression_ratio': 1.37, 'depth': 1, 10388 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 1, 10389 'name': 'MAXSALX', 'nodes': 31, 'ratio': 0.03, 'root_page': 286, 'total_dup': 5}, 10390 {'avg_data_length': 10.29, 'avg_key_length': 13.03, 'avg_node_length': 14.06, 'avg_prefix_length': 8.48, 10391 'clustering_factor': 1.0, 'compression_ratio': 1.44, 'depth': 1, 10392 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 2, 10393 'name': 'MINSALX', 'nodes': 31, 'ratio': 0.03, 'root_page': 287, 'total_dup': 7}, 10394 {'avg_data_length': 1.39, 'avg_key_length': 3.39, 'avg_node_length': 4.61, 'avg_prefix_length': 2.77, 10395 'clustering_factor': 1.0, 'compression_ratio': 1.23, 'depth': 1, 10396 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 20, 10397 'name': 'RDB$FOREIGN3', 'nodes': 31, 'ratio': 0.03, 'root_page': 192, 'total_dup': 24}, 10398 {'avg_data_length': 10.45, 'avg_key_length': 13.42, 'avg_node_length': 14.45, 'avg_prefix_length': 6.19, 10399 'clustering_factor': 1.0, 'compression_ratio': 1.24, 'depth': 1, 10400 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10401 'name': 'RDB$PRIMARY2', 'nodes': 31, 'ratio': 0.03, 'root_page': 191, 'total_dup': 0}, 10402 {'avg_data_length': 22.5, 'avg_key_length': 25.33, 'avg_node_length': 26.5, 'avg_prefix_length': 4.17, 10403 'clustering_factor': 1.0, 'compression_ratio': 1.05, 'depth': 1, 10404 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 0, 10405 'name': 'PRODTYPEX', 'nodes': 6, 'ratio': 0.17, 'root_page': 288, 'total_dup': 0}, 10406 {'avg_data_length': 13.33, 'avg_key_length': 15.5, 'avg_node_length': 17.33, 'avg_prefix_length': 0.33, 10407 'clustering_factor': 1.0, 'compression_ratio': 0.88, 'depth': 1, 10408 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10409 'name': 'RDB$11', 'nodes': 6, 'ratio': 0.17, 'root_page': 222, 'total_dup': 0}, 10410 {'avg_data_length': 1.33, 'avg_key_length': 3.5, 'avg_node_length': 4.67, 'avg_prefix_length': 0.67, 10411 'clustering_factor': 1.0, 'compression_ratio': 0.57, 'depth': 1, 10412 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 0, 10413 'name': 'RDB$FOREIGN13', 'nodes': 6, 'ratio': 0.17, 'root_page': 232, 'total_dup': 0}, 10414 {'avg_data_length': 4.83, 'avg_key_length': 7.0, 'avg_node_length': 8.83, 'avg_prefix_length': 0.17, 10415 'clustering_factor': 1.0, 'compression_ratio': 0.71, 'depth': 1, 10416 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 10417 'name': 'RDB$PRIMARY12', 'nodes': 6, 'ratio': 0.17, 'root_page': 223, 'total_dup': 0}, 10418 {'avg_data_length': 0.71, 'avg_key_length': 2.79, 'avg_node_length': 3.92, 'avg_prefix_length': 2.29, 10419 'clustering_factor': 1.0, 'compression_ratio': 1.07, 'depth': 1, 10420 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 5, 10421 'name': 'RDB$FOREIGN18', 'nodes': 24, 'ratio': 0.04, 'root_page': 250, 'total_dup': 15}, 10422 {'avg_data_length': 1.0, 'avg_key_length': 3.04, 'avg_node_length': 4.21, 'avg_prefix_length': 4.0, 10423 'clustering_factor': 1.0, 'compression_ratio': 1.64, 'depth': 1, 10424 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 8, 10425 'name': 'RDB$FOREIGN19', 'nodes': 24, 'ratio': 0.04, 'root_page': 251, 'total_dup': 19}, 10426 {'avg_data_length': 6.83, 'avg_key_length': 9.67, 'avg_node_length': 10.71, 'avg_prefix_length': 12.17, 10427 'clustering_factor': 1.0, 'compression_ratio': 1.97, 'depth': 1, 10428 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10429 'name': 'RDB$PRIMARY17', 'nodes': 24, 'ratio': 0.04, 'root_page': 249, 'total_dup': 0}, 10430 {'avg_data_length': 0.31, 'avg_key_length': 2.35, 'avg_node_length': 3.37, 'avg_prefix_length': 6.69, 10431 'clustering_factor': 1.0, 'compression_ratio': 2.98, 'depth': 1, 10432 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 21, 10433 'name': 'CHANGEX', 'nodes': 49, 'ratio': 0.02, 'root_page': 289, 'total_dup': 46}, 10434 {'avg_data_length': 0.9, 'avg_key_length': 3.1, 'avg_node_length': 4.12, 'avg_prefix_length': 1.43, 10435 'clustering_factor': 1.0, 'compression_ratio': 0.75, 'depth': 1, 10436 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 2, 10437 'name': 'RDB$FOREIGN21', 'nodes': 49, 'ratio': 0.02, 'root_page': 256, 'total_dup': 16}, 10438 {'avg_data_length': 18.29, 'avg_key_length': 21.27, 'avg_node_length': 22.29, 'avg_prefix_length': 4.31, 10439 'clustering_factor': 1.0, 'compression_ratio': 1.06, 'depth': 1, 10440 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10441 'name': 'RDB$PRIMARY20', 'nodes': 49, 'ratio': 0.02, 'root_page': 255, 'total_dup': 0}, 10442 {'avg_data_length': 0.29, 'avg_key_length': 2.29, 'avg_node_length': 3.35, 'avg_prefix_length': 5.39, 10443 'clustering_factor': 1.0, 'compression_ratio': 2.48, 'depth': 1, 10444 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 28, 10445 'name': 'UPDATERX', 'nodes': 49, 'ratio': 0.02, 'root_page': 290, 'total_dup': 46}, 10446 {'avg_data_length': 2.55, 'avg_key_length': 4.94, 'avg_node_length': 5.97, 'avg_prefix_length': 2.88, 10447 'clustering_factor': 1.0, 'compression_ratio': 1.1, 'depth': 1, 10448 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 6, 10449 'name': 'NEEDX', 'nodes': 33, 'ratio': 0.03, 'root_page': 291, 'total_dup': 11}, 10450 {'avg_data_length': 1.85, 'avg_key_length': 4.03, 'avg_node_length': 5.06, 'avg_prefix_length': 11.18, 10451 'clustering_factor': 1.0, 'compression_ratio': 3.23, 'depth': 1, 10452 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 'leaf_buckets': 1, 'max_dup': 3, 10453 'name': 'QTYX', 'nodes': 33, 'ratio': 0.03, 'root_page': 292, 'total_dup': 11}, 10454 {'avg_data_length': 0.52, 'avg_key_length': 2.52, 'avg_node_length': 3.55, 'avg_prefix_length': 2.48, 10455 'clustering_factor': 1.0, 'compression_ratio': 1.19, 'depth': 1, 10456 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 4, 10457 'name': 'RDB$FOREIGN25', 'nodes': 33, 'ratio': 0.03, 'root_page': 270, 'total_dup': 18}, 10458 {'avg_data_length': 0.45, 'avg_key_length': 2.64, 'avg_node_length': 3.67, 'avg_prefix_length': 2.21, 10459 'clustering_factor': 1.0, 'compression_ratio': 1.01, 'depth': 1, 10460 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 7, 10461 'name': 'RDB$FOREIGN26', 'nodes': 33, 'ratio': 0.03, 'root_page': 271, 'total_dup': 25}, 10462 {'avg_data_length': 4.48, 'avg_key_length': 7.42, 'avg_node_length': 8.45, 'avg_prefix_length': 3.52, 10463 'clustering_factor': 1.0, 'compression_ratio': 1.08, 'depth': 1, 10464 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10465 'name': 'RDB$PRIMARY24', 'nodes': 33, 'ratio': 0.03, 'root_page': 269, 'total_dup': 0}, 10466 {'avg_data_length': 0.97, 'avg_key_length': 3.03, 'avg_node_length': 4.06, 'avg_prefix_length': 9.82, 10467 'clustering_factor': 1.0, 'compression_ratio': 3.56, 'depth': 1, 10468 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 5, 'leaf_buckets': 1, 'max_dup': 14, 10469 'name': 'SALESTATX', 'nodes': 33, 'ratio': 0.03, 'root_page': 293, 'total_dup': 27}, 10470 {'avg_data_length': 0.0, 'avg_key_length': 0.0, 'avg_node_length': 0.0, 'avg_prefix_length': 0.0, 10471 'clustering_factor': 0.0, 'compression_ratio': 0.0, 'depth': 1, 10472 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10473 'name': 'RDB$PRIMARY28', 'nodes': 0, 'ratio': 0.0, 'root_page': 317, 'total_dup': 0}] 10474 i = 0 10475 while i < len(db.tables): 10476 self.assertDictEqual(data[i], get_object_data(db.indices[i], ['table']), 'Unexpected output from parser (indices)') 10477 i += 1 10478 def test_parse30_r(self): 10479 db = self._parse_file(os.path.join(self.dbpath, 'gstat30-r.out')) 10480 # 10481 self.assertTrue(db.has_table_stats()) 10482 self.assertTrue(db.has_index_stats()) 10483 self.assertTrue(db.has_row_stats()) 10484 self.assertFalse(db.has_encryption_stats()) 10485 self.assertFalse(db.has_system()) 10486 # Tables 10487 data = [{'avg_fill': 86, 'avg_fragment_length': 0.0, 'avg_record_length': 2.79, 'avg_unpacked_length': 120.0, 10488 'avg_version_length': 16.61, 'blob_pages': 0, 'blobs': 125, 'blobs_total_length': 11237, 'compression_ratio': 42.99, 10489 'data_page_slots': 3, 'data_pages': 3, 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=1, d100=2), 10490 'empty_pages': 0, 'full_pages': 1, 'index_root_page': 299, 'indices': 0, 'level_0': 125, 'level_1': 0, 'level_2': 0, 10491 'max_fragments': 0, 'max_versions': 1, 'name': 'AR', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 297, 10492 'secondary_pages': 2, 'swept_pages': 0, 'table_id': 140, 'total_formats': 1, 'total_fragments': 0, 'total_records': 120, 10493 'total_versions': 105, 'used_formats': 1}, 10494 {'avg_fill': 8, 'avg_fragment_length': 0.0, 'avg_record_length': 25.94, 'avg_unpacked_length': 34.0, 10495 'avg_version_length': 0.0, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': 1.31, 10496 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 10497 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 183, 'indices': 1, 'level_0': None, 'level_1': None, 'level_2': None, 10498 'max_fragments': 0, 'max_versions': 0, 'name': 'COUNTRY', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 182, 10499 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 128, 'total_formats': 1, 'total_fragments': 0, 'total_records': 16, 10500 'total_versions': 0, 'used_formats': 1}, 10501 {'avg_fill': 26, 'avg_fragment_length': 0.0, 'avg_record_length': 125.47, 'avg_unpacked_length': 241.0, 10502 'avg_version_length': 0.0, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': 1.92, 10503 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 10504 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 262, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 10505 'max_fragments': 0, 'max_versions': 0, 'name': 'CUSTOMER', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 261, 10506 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 137, 'total_formats': 1, 'total_fragments': 0, 'total_records': 15, 10507 'total_versions': 0, 'used_formats': 1}, 10508 {'avg_fill': 24, 'avg_fragment_length': 0.0, 'avg_record_length': 74.62, 'avg_unpacked_length': 88.0, 10509 'avg_version_length': 0.0, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': 1.18, 10510 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 10511 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 199, 'indices': 5, 'level_0': None, 'level_1': None, 'level_2': None, 10512 'max_fragments': 0, 'max_versions': 0, 'name': 'DEPARTMENT', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 198, 10513 'secondary_pages': 0, 'swept_pages': 1, 'table_id': 130, 'total_formats': 1, 'total_fragments': 0, 'total_records': 21, 10514 'total_versions': 0, 'used_formats': 1}, 10515 {'avg_fill': 44, 'avg_fragment_length': 0.0, 'avg_record_length': 69.02, 'avg_unpacked_length': 39.0, 10516 'avg_version_length': 0.0, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': 0.57, 10517 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=0, d50=1, d80=0, d100=0), 10518 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 213, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 10519 'max_fragments': 0, 'max_versions': 0, 'name': 'EMPLOYEE', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 212, 10520 'secondary_pages': 0, 'swept_pages': 1, 'table_id': 131, 'total_formats': 1, 'total_fragments': 0, 'total_records': 42, 10521 'total_versions': 0, 'used_formats': 1}, 10522 {'avg_fill': 10, 'avg_fragment_length': 0.0, 'avg_record_length': 12.0, 'avg_unpacked_length': 11.0, 10523 'avg_version_length': 0.0, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': 0.92, 10524 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 10525 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 235, 'indices': 3, 'level_0': None, 'level_1': None, 'level_2': None, 10526 'max_fragments': 0, 'max_versions': 0, 'name': 'EMPLOYEE_PROJECT', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 234, 10527 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 134, 'total_formats': 1, 'total_fragments': 0, 'total_records': 28, 10528 'total_versions': 0, 'used_formats': 1}, 10529 {'avg_fill': 54, 'avg_fragment_length': 0.0, 'avg_record_length': 66.13, 'avg_unpacked_length': 96.0, 10530 'avg_version_length': 0.0, 'blob_pages': 0, 'blobs': 39, 'blobs_total_length': 4840, 'compression_ratio': 1.45, 10531 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=1, d100=0), 10532 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 190, 'indices': 4, 'level_0': 39, 'level_1': 0, 'level_2': 0, 10533 'max_fragments': 0, 'max_versions': 0, 'name': 'JOB', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 189, 10534 'secondary_pages': 1, 'swept_pages': 1, 'table_id': 129, 'total_formats': 1, 'total_fragments': 0, 'total_records': 31, 10535 'total_versions': 0, 'used_formats': 1}, 10536 {'avg_fill': 7, 'avg_fragment_length': 0.0, 'avg_record_length': 49.67, 'avg_unpacked_length': 56.0, 10537 'avg_version_length': 0.0, 'blob_pages': 0, 'blobs': 6, 'blobs_total_length': 548, 'compression_ratio': 1.13, 10538 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=2, d40=0, d50=0, d80=0, d100=0), 10539 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 221, 'indices': 4, 'level_0': 6, 'level_1': 0, 'level_2': 0, 10540 'max_fragments': 0, 'max_versions': 0, 'name': 'PROJECT', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 220, 10541 'secondary_pages': 1, 'swept_pages': 1, 'table_id': 133, 'total_formats': 1, 'total_fragments': 0, 'total_records': 6, 10542 'total_versions': 0, 'used_formats': 1}, 10543 {'avg_fill': 20, 'avg_fragment_length': 0.0, 'avg_record_length': 30.58, 'avg_unpacked_length': 32.0, 10544 'avg_version_length': 0.0, 'blob_pages': 0, 'blobs': 24, 'blobs_total_length': 1344, 'compression_ratio': 1.05, 10545 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=1, d40=1, d50=0, d80=0, d100=0), 10546 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 248, 'indices': 3, 'level_0': 24, 'level_1': 0, 'level_2': 0, 10547 'max_fragments': 0, 'max_versions': 0, 'name': 'PROJ_DEPT_BUDGET', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 239, 10548 'secondary_pages': 1, 'swept_pages': 0, 'table_id': 135, 'total_formats': 1, 'total_fragments': 0, 'total_records': 24, 10549 'total_versions': 0, 'used_formats': 1}, 10550 {'avg_fill': 30, 'avg_fragment_length': 0.0, 'avg_record_length': 33.29, 'avg_unpacked_length': 8.0, 10551 'avg_version_length': 0.0, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': 0.24, 10552 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 10553 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 254, 'indices': 4, 'level_0': None, 'level_1': None, 'level_2': None, 10554 'max_fragments': 0, 'max_versions': 0, 'name': 'SALARY_HISTORY', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 253, 10555 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 136, 'total_formats': 1, 'total_fragments': 0, 'total_records': 49, 10556 'total_versions': 0, 'used_formats': 1}, 10557 {'avg_fill': 35, 'avg_fragment_length': 0.0, 'avg_record_length': 68.82, 'avg_unpacked_length': 8.0, 10558 'avg_version_length': 0.0, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': 0.12, 10559 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=0, d40=1, d50=0, d80=0, d100=0), 10560 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 268, 'indices': 6, 'level_0': None, 'level_1': None, 'level_2': None, 10561 'max_fragments': 0, 'max_versions': 0, 'name': 'SALES', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 267, 10562 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 138, 'total_formats': 1, 'total_fragments': 0, 'total_records': 33, 10563 'total_versions': 0, 'used_formats': 1}, 10564 {'avg_fill': 0, 'avg_fragment_length': 0.0, 'avg_record_length': 0.0, 'avg_unpacked_length': 0.0, 10565 'avg_version_length': 0.0, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': 0.0, 10566 'data_page_slots': 0, 'data_pages': 0, 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 10567 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 324, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10568 'max_fragments': 0, 'max_versions': 0, 'name': 'T', 'pointer_pages': 1, 'primary_pages': 0, 'primary_pointer_page': 323, 10569 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 147, 'total_formats': 1, 'total_fragments': 0, 'total_records': 0, 10570 'total_versions': 0, 'used_formats': 0}, 10571 {'avg_fill': 8, 'avg_fragment_length': 0.0, 'avg_record_length': 0.0, 'avg_unpacked_length': 120.0, 10572 'avg_version_length': 14.25, 'blob_pages': 0, 'blobs': 3, 'blobs_total_length': 954, 'compression_ratio': 0.0, 10573 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=2, d40=0, d50=0, d80=0, d100=0), 10574 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 303, 'indices': 0, 'level_0': 3, 'level_1': 0, 'level_2': 0, 10575 'max_fragments': 0, 'max_versions': 1, 'name': 'T2', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 302, 10576 'secondary_pages': 1, 'swept_pages': 0, 'table_id': 142, 'total_formats': 1, 'total_fragments': 0, 'total_records': 4, 10577 'total_versions': 4, 'used_formats': 1}, 10578 {'avg_fill': 3, 'avg_fragment_length': 0.0, 'avg_record_length': 0.0, 'avg_unpacked_length': 112.0, 10579 'avg_version_length': 22.67, 'blob_pages': 0, 'blobs': 2, 'blobs_total_length': 313, 'compression_ratio': 0.0, 10580 'data_page_slots': 2, 'data_pages': 2, 'distribution': FillDistribution(d20=2, d40=0, d50=0, d80=0, d100=0), 10581 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 306, 'indices': 0, 'level_0': 2, 'level_1': 0, 'level_2': 0, 10582 'max_fragments': 0, 'max_versions': 1, 'name': 'T3', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 305, 10583 'secondary_pages': 1, 'swept_pages': 0, 'table_id': 143, 'total_formats': 1, 'total_fragments': 0, 'total_records': 3, 10584 'total_versions': 3, 'used_formats': 1}, 10585 {'avg_fill': 3, 'avg_fragment_length': 0.0, 'avg_record_length': 0.0, 'avg_unpacked_length': 264.0, 10586 'avg_version_length': 75.0, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': 0.0, 10587 'data_page_slots': 1, 'data_pages': 1, 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 10588 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 308, 'indices': 0, 'level_0': None, 'level_1': None, 'level_2': None, 10589 'max_fragments': 0, 'max_versions': 1, 'name': 'T4', 'pointer_pages': 1, 'primary_pages': 1, 'primary_pointer_page': 307, 10590 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 144, 'total_formats': 1, 'total_fragments': 0, 'total_records': 2, 10591 'total_versions': 2, 'used_formats': 1}, 10592 {'avg_fill': 0, 'avg_fragment_length': 0.0, 'avg_record_length': 0.0, 'avg_unpacked_length': 0.0, 10593 'avg_version_length': 0.0, 'blob_pages': None, 'blobs': None, 'blobs_total_length': None, 'compression_ratio': 0.0, 10594 'data_page_slots': 0, 'data_pages': 0, 'distribution': FillDistribution(d20=0, d40=0, d50=0, d80=0, d100=0), 10595 'empty_pages': 0, 'full_pages': 0, 'index_root_page': 316, 'indices': 1, 'level_0': None, 'level_1': None, 'level_2': None, 10596 'max_fragments': 0, 'max_versions': 0, 'name': 'T5', 'pointer_pages': 1, 'primary_pages': 0, 'primary_pointer_page': 315, 10597 'secondary_pages': 0, 'swept_pages': 0, 'table_id': 145, 'total_formats': 1, 'total_fragments': 0, 'total_records': 0, 10598 'total_versions': 0, 'used_formats': 0}] 10599 i = 0 10600 while i < len(db.tables): 10601 self.assertDictEqual(data[i], get_object_data(db.tables[i]), 'Unexpected output from parser (tables)') 10602 i += 1 10603 # Indices 10604 data = [{'avg_data_length': 6.44, 'avg_key_length': 8.63, 'avg_node_length': 10.44, 'avg_prefix_length': 0.44, 10605 'clustering_factor': 1.0, 'compression_ratio': 0.8, 'depth': 1, 10606 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10607 'name': 'RDB$PRIMARY1', 'nodes': 16, 'ratio': 0.06, 'root_page': 186, 'total_dup': 0}, 10608 {'avg_data_length': 15.87, 'avg_key_length': 18.27, 'avg_node_length': 19.87, 'avg_prefix_length': 0.6, 10609 'clustering_factor': 1.0, 'compression_ratio': 0.9, 'depth': 1, 10610 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 0, 10611 'name': 'CUSTNAMEX', 'nodes': 15, 'ratio': 0.07, 'root_page': 276, 'total_dup': 0}, 10612 {'avg_data_length': 17.27, 'avg_key_length': 20.2, 'avg_node_length': 21.27, 'avg_prefix_length': 2.33, 10613 'clustering_factor': 1.0, 'compression_ratio': 0.97, 'depth': 1, 10614 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 0, 10615 'name': 'CUSTREGION', 'nodes': 15, 'ratio': 0.07, 'root_page': 283, 'total_dup': 0}, 10616 {'avg_data_length': 4.87, 'avg_key_length': 6.93, 'avg_node_length': 8.6, 'avg_prefix_length': 0.87, 10617 'clustering_factor': 1.0, 'compression_ratio': 0.83, 'depth': 1, 10618 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 4, 10619 'name': 'RDB$FOREIGN23', 'nodes': 15, 'ratio': 0.07, 'root_page': 264, 'total_dup': 4}, 10620 {'avg_data_length': 1.13, 'avg_key_length': 3.13, 'avg_node_length': 4.2, 'avg_prefix_length': 1.87, 10621 'clustering_factor': 1.0, 'compression_ratio': 0.96, 'depth': 1, 10622 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10623 'name': 'RDB$PRIMARY22', 'nodes': 15, 'ratio': 0.07, 'root_page': 263, 'total_dup': 0}, 10624 {'avg_data_length': 5.38, 'avg_key_length': 8.0, 'avg_node_length': 9.05, 'avg_prefix_length': 3.62, 10625 'clustering_factor': 1.0, 'compression_ratio': 1.13, 'depth': 1, 10626 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 3, 10627 'name': 'BUDGETX', 'nodes': 21, 'ratio': 0.05, 'root_page': 284, 'total_dup': 7}, 10628 {'avg_data_length': 13.95, 'avg_key_length': 16.57, 'avg_node_length': 17.95, 'avg_prefix_length': 5.29, 10629 'clustering_factor': 1.0, 'compression_ratio': 1.16, 'depth': 1, 10630 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10631 'name': 'RDB$4', 'nodes': 21, 'ratio': 0.05, 'root_page': 208, 'total_dup': 0}, 10632 {'avg_data_length': 1.14, 'avg_key_length': 3.24, 'avg_node_length': 4.29, 'avg_prefix_length': 0.81, 10633 'clustering_factor': 1.0, 'compression_ratio': 0.6, 'depth': 1, 10634 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 'leaf_buckets': 1, 'max_dup': 3, 10635 'name': 'RDB$FOREIGN10', 'nodes': 21, 'ratio': 0.05, 'root_page': 219, 'total_dup': 3}, 10636 {'avg_data_length': 0.81, 'avg_key_length': 2.95, 'avg_node_length': 4.1, 'avg_prefix_length': 2.05, 10637 'clustering_factor': 1.0, 'compression_ratio': 0.97, 'depth': 1, 10638 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 4, 10639 'name': 'RDB$FOREIGN6', 'nodes': 21, 'ratio': 0.05, 'root_page': 210, 'total_dup': 13}, 10640 {'avg_data_length': 1.71, 'avg_key_length': 4.05, 'avg_node_length': 5.24, 'avg_prefix_length': 1.29, 10641 'clustering_factor': 1.0, 'compression_ratio': 0.74, 'depth': 1, 10642 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 10643 'name': 'RDB$PRIMARY5', 'nodes': 21, 'ratio': 0.05, 'root_page': 209, 'total_dup': 0}, 10644 {'avg_data_length': 15.52, 'avg_key_length': 18.5, 'avg_node_length': 19.52, 'avg_prefix_length': 2.17, 10645 'clustering_factor': 1.0, 'compression_ratio': 0.96, 'depth': 1, 10646 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 0, 10647 'name': 'NAMEX', 'nodes': 42, 'ratio': 0.02, 'root_page': 285, 'total_dup': 0}, 10648 {'avg_data_length': 0.81, 'avg_key_length': 2.98, 'avg_node_length': 4.07, 'avg_prefix_length': 2.19, 10649 'clustering_factor': 1.0, 'compression_ratio': 1.01, 'depth': 1, 10650 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 4, 10651 'name': 'RDB$FOREIGN8', 'nodes': 42, 'ratio': 0.02, 'root_page': 215, 'total_dup': 23}, 10652 {'avg_data_length': 6.79, 'avg_key_length': 9.4, 'avg_node_length': 10.43, 'avg_prefix_length': 9.05, 10653 'clustering_factor': 1.0, 'compression_ratio': 1.68, 'depth': 1, 10654 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 4, 10655 'name': 'RDB$FOREIGN9', 'nodes': 42, 'ratio': 0.02, 'root_page': 216, 'total_dup': 15}, 10656 {'avg_data_length': 1.31, 'avg_key_length': 3.6, 'avg_node_length': 4.62, 'avg_prefix_length': 1.17, 10657 'clustering_factor': 1.0, 'compression_ratio': 0.69, 'depth': 1, 10658 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10659 'name': 'RDB$PRIMARY7', 'nodes': 42, 'ratio': 0.02, 'root_page': 214, 'total_dup': 0}, 10660 {'avg_data_length': 1.04, 'avg_key_length': 3.25, 'avg_node_length': 4.29, 'avg_prefix_length': 1.36, 10661 'clustering_factor': 1.0, 'compression_ratio': 0.74, 'depth': 1, 10662 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 2, 10663 'name': 'RDB$FOREIGN15', 'nodes': 28, 'ratio': 0.04, 'root_page': 237, 'total_dup': 6}, 10664 {'avg_data_length': 0.86, 'avg_key_length': 2.89, 'avg_node_length': 4.04, 'avg_prefix_length': 4.14, 10665 'clustering_factor': 1.0, 'compression_ratio': 1.73, 'depth': 1, 10666 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 9, 10667 'name': 'RDB$FOREIGN16', 'nodes': 28, 'ratio': 0.04, 'root_page': 238, 'total_dup': 23}, 10668 {'avg_data_length': 9.11, 'avg_key_length': 12.07, 'avg_node_length': 13.11, 'avg_prefix_length': 2.89, 10669 'clustering_factor': 1.0, 'compression_ratio': 0.99, 'depth': 1, 10670 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10671 'name': 'RDB$PRIMARY14', 'nodes': 28, 'ratio': 0.04, 'root_page': 236, 'total_dup': 0}, 10672 {'avg_data_length': 10.9, 'avg_key_length': 13.71, 'avg_node_length': 14.74, 'avg_prefix_length': 7.87, 10673 'clustering_factor': 1.0, 'compression_ratio': 1.37, 'depth': 1, 10674 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 1, 10675 'name': 'MAXSALX', 'nodes': 31, 'ratio': 0.03, 'root_page': 286, 'total_dup': 5}, 10676 {'avg_data_length': 10.29, 'avg_key_length': 13.03, 'avg_node_length': 14.06, 'avg_prefix_length': 8.48, 10677 'clustering_factor': 1.0, 'compression_ratio': 1.44, 'depth': 1, 10678 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 2, 10679 'name': 'MINSALX', 'nodes': 31, 'ratio': 0.03, 'root_page': 287, 'total_dup': 7}, 10680 {'avg_data_length': 1.39, 'avg_key_length': 3.39, 'avg_node_length': 4.61, 'avg_prefix_length': 2.77, 10681 'clustering_factor': 1.0, 'compression_ratio': 1.23, 'depth': 1, 10682 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 20, 10683 'name': 'RDB$FOREIGN3', 'nodes': 31, 'ratio': 0.03, 'root_page': 192, 'total_dup': 24}, 10684 {'avg_data_length': 10.45, 'avg_key_length': 13.42, 'avg_node_length': 14.45, 'avg_prefix_length': 6.19, 10685 'clustering_factor': 1.0, 'compression_ratio': 1.24, 'depth': 1, 10686 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10687 'name': 'RDB$PRIMARY2', 'nodes': 31, 'ratio': 0.03, 'root_page': 191, 'total_dup': 0}, 10688 {'avg_data_length': 22.5, 'avg_key_length': 25.33, 'avg_node_length': 26.5, 'avg_prefix_length': 4.17, 10689 'clustering_factor': 1.0, 'compression_ratio': 1.05, 'depth': 1, 10690 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 0, 10691 'name': 'PRODTYPEX', 'nodes': 6, 'ratio': 0.17, 'root_page': 288, 'total_dup': 0}, 10692 {'avg_data_length': 13.33, 'avg_key_length': 15.5, 'avg_node_length': 17.33, 'avg_prefix_length': 0.33, 10693 'clustering_factor': 1.0, 'compression_ratio': 0.88, 'depth': 1, 10694 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10695 'name': 'RDB$11', 'nodes': 6, 'ratio': 0.17, 'root_page': 222, 'total_dup': 0}, 10696 {'avg_data_length': 1.33, 'avg_key_length': 3.5, 'avg_node_length': 4.67, 'avg_prefix_length': 0.67, 10697 'clustering_factor': 1.0, 'compression_ratio': 0.57, 'depth': 1, 10698 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 0, 10699 'name': 'RDB$FOREIGN13', 'nodes': 6, 'ratio': 0.17, 'root_page': 232, 'total_dup': 0}, 10700 {'avg_data_length': 4.83, 'avg_key_length': 7.0, 'avg_node_length': 8.83, 'avg_prefix_length': 0.17, 10701 'clustering_factor': 1.0, 'compression_ratio': 0.71, 'depth': 1, 10702 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 0, 10703 'name': 'RDB$PRIMARY12', 'nodes': 6, 'ratio': 0.17, 'root_page': 223, 'total_dup': 0}, 10704 {'avg_data_length': 0.71, 'avg_key_length': 2.79, 'avg_node_length': 3.92, 'avg_prefix_length': 2.29, 10705 'clustering_factor': 1.0, 'compression_ratio': 1.07, 'depth': 1, 10706 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 5, 10707 'name': 'RDB$FOREIGN18', 'nodes': 24, 'ratio': 0.04, 'root_page': 250, 'total_dup': 15}, 10708 {'avg_data_length': 1.0, 'avg_key_length': 3.04, 'avg_node_length': 4.21, 'avg_prefix_length': 4.0, 10709 'clustering_factor': 1.0, 'compression_ratio': 1.64, 'depth': 1, 10710 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 8, 10711 'name': 'RDB$FOREIGN19', 'nodes': 24, 'ratio': 0.04, 'root_page': 251, 'total_dup': 19}, 10712 {'avg_data_length': 6.83, 'avg_key_length': 9.67, 'avg_node_length': 10.71, 'avg_prefix_length': 12.17, 10713 'clustering_factor': 1.0, 'compression_ratio': 1.97, 'depth': 1, 10714 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10715 'name': 'RDB$PRIMARY17', 'nodes': 24, 'ratio': 0.04, 'root_page': 249, 'total_dup': 0}, 10716 {'avg_data_length': 0.31, 'avg_key_length': 2.35, 'avg_node_length': 3.37, 'avg_prefix_length': 6.69, 10717 'clustering_factor': 1.0, 'compression_ratio': 2.98, 'depth': 1, 10718 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 21, 10719 'name': 'CHANGEX', 'nodes': 49, 'ratio': 0.02, 'root_page': 289, 'total_dup': 46}, 10720 {'avg_data_length': 0.9, 'avg_key_length': 3.1, 'avg_node_length': 4.12, 'avg_prefix_length': 1.43, 10721 'clustering_factor': 1.0, 'compression_ratio': 0.75, 'depth': 1, 10722 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 2, 10723 'name': 'RDB$FOREIGN21', 'nodes': 49, 'ratio': 0.02, 'root_page': 256, 'total_dup': 16}, 10724 {'avg_data_length': 18.29, 'avg_key_length': 21.27, 'avg_node_length': 22.29, 'avg_prefix_length': 4.31, 10725 'clustering_factor': 1.0, 'compression_ratio': 1.06, 'depth': 1, 10726 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10727 'name': 'RDB$PRIMARY20', 'nodes': 49, 'ratio': 0.02, 'root_page': 255, 'total_dup': 0}, 10728 {'avg_data_length': 0.29, 'avg_key_length': 2.29, 'avg_node_length': 3.35, 'avg_prefix_length': 5.39, 10729 'clustering_factor': 1.0, 'compression_ratio': 2.48, 'depth': 1, 10730 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 28, 10731 'name': 'UPDATERX', 'nodes': 49, 'ratio': 0.02, 'root_page': 290, 'total_dup': 46}, 10732 {'avg_data_length': 2.55, 'avg_key_length': 4.94, 'avg_node_length': 5.97, 'avg_prefix_length': 2.88, 10733 'clustering_factor': 1.0, 'compression_ratio': 1.1, 'depth': 1, 10734 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 3, 'leaf_buckets': 1, 'max_dup': 6, 10735 'name': 'NEEDX', 'nodes': 33, 'ratio': 0.03, 'root_page': 291, 'total_dup': 11}, 10736 {'avg_data_length': 1.85, 'avg_key_length': 4.03, 'avg_node_length': 5.06, 'avg_prefix_length': 11.18, 10737 'clustering_factor': 1.0, 'compression_ratio': 3.23, 'depth': 1, 10738 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 4, 'leaf_buckets': 1, 'max_dup': 3, 10739 'name': 'QTYX', 'nodes': 33, 'ratio': 0.03, 'root_page': 292, 'total_dup': 11}, 10740 {'avg_data_length': 0.52, 'avg_key_length': 2.52, 'avg_node_length': 3.55, 'avg_prefix_length': 2.48, 10741 'clustering_factor': 1.0, 'compression_ratio': 1.19, 'depth': 1, 10742 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 1, 'leaf_buckets': 1, 'max_dup': 4, 10743 'name': 'RDB$FOREIGN25', 'nodes': 33, 'ratio': 0.03, 'root_page': 270, 'total_dup': 18}, 10744 {'avg_data_length': 0.45, 'avg_key_length': 2.64, 'avg_node_length': 3.67, 'avg_prefix_length': 2.21, 10745 'clustering_factor': 1.0, 'compression_ratio': 1.01, 'depth': 1, 10746 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 2, 'leaf_buckets': 1, 'max_dup': 7, 10747 'name': 'RDB$FOREIGN26', 'nodes': 33, 'ratio': 0.03, 'root_page': 271, 'total_dup': 25}, 10748 {'avg_data_length': 4.48, 'avg_key_length': 7.42, 'avg_node_length': 8.45, 'avg_prefix_length': 3.52, 10749 'clustering_factor': 1.0, 'compression_ratio': 1.08, 'depth': 1, 10750 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10751 'name': 'RDB$PRIMARY24', 'nodes': 33, 'ratio': 0.03, 'root_page': 269, 'total_dup': 0}, 10752 {'avg_data_length': 0.97, 'avg_key_length': 3.03, 'avg_node_length': 4.06, 'avg_prefix_length': 9.82, 10753 'clustering_factor': 1.0, 'compression_ratio': 3.56, 'depth': 1, 10754 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 5, 'leaf_buckets': 1, 'max_dup': 14, 10755 'name': 'SALESTATX', 'nodes': 33, 'ratio': 0.03, 'root_page': 293, 'total_dup': 27}, 10756 {'avg_data_length': 0.0, 'avg_key_length': 0.0, 'avg_node_length': 0.0, 'avg_prefix_length': 0.0, 10757 'clustering_factor': 0.0, 'compression_ratio': 0.0, 'depth': 1, 10758 'distribution': FillDistribution(d20=1, d40=0, d50=0, d80=0, d100=0), 'index_id': 0, 'leaf_buckets': 1, 'max_dup': 0, 10759 'name': 'RDB$PRIMARY28', 'nodes': 0, 'ratio': 0.0, 'root_page': 317, 'total_dup': 0}] 10760 i = 0 10761 while i < len(db.tables): 10762 self.assertDictEqual(data[i], get_object_data(db.indices[i], ['table']), 'Unexpected output from parser (indices)') 10763 i += 1 10764 def test_parse30_s(self): 10765 db = self._parse_file(os.path.join(self.dbpath, 'gstat30-s.out')) 10766 # 10767 self.assertTrue(db.has_table_stats()) 10768 self.assertTrue(db.has_index_stats()) 10769 self.assertFalse(db.has_row_stats()) 10770 self.assertFalse(db.has_encryption_stats()) 10771 self.assertTrue(db.has_system()) 10772 # Check system tables 10773 data = ['RDB$AUTH_MAPPING', 'RDB$BACKUP_HISTORY', 'RDB$CHARACTER_SETS', 'RDB$CHECK_CONSTRAINTS', 'RDB$COLLATIONS', 'RDB$DATABASE', 10774 'RDB$DB_CREATORS', 'RDB$DEPENDENCIES', 'RDB$EXCEPTIONS', 'RDB$FIELDS', 'RDB$FIELD_DIMENSIONS', 'RDB$FILES', 'RDB$FILTERS', 10775 'RDB$FORMATS', 'RDB$FUNCTIONS', 'RDB$FUNCTION_ARGUMENTS', 'RDB$GENERATORS', 'RDB$INDEX_SEGMENTS', 'RDB$INDICES', 10776 'RDB$LOG_FILES', 'RDB$PACKAGES', 'RDB$PAGES', 'RDB$PROCEDURES', 'RDB$PROCEDURE_PARAMETERS', 'RDB$REF_CONSTRAINTS', 10777 'RDB$RELATIONS', 'RDB$RELATION_CONSTRAINTS', 'RDB$RELATION_FIELDS', 'RDB$ROLES', 'RDB$SECURITY_CLASSES', 'RDB$TRANSACTIONS', 10778 'RDB$TRIGGERS', 'RDB$TRIGGER_MESSAGES', 'RDB$TYPES', 'RDB$USER_PRIVILEGES', 'RDB$VIEW_RELATIONS'] 10779 for table in db.tables: 10780 if table.name.startswith('RDB$'): 10781 self.assertIn(table.name, data) 10782 # check system indices 10783 data = ['RDB$PRIMARY1', 'RDB$FOREIGN23', 'RDB$PRIMARY22', 'RDB$4', 'RDB$FOREIGN10', 'RDB$FOREIGN6', 'RDB$PRIMARY5', 'RDB$FOREIGN8', 10784 'RDB$FOREIGN9', 'RDB$PRIMARY7', 'RDB$FOREIGN15', 'RDB$FOREIGN16', 'RDB$PRIMARY14', 'RDB$FOREIGN3', 'RDB$PRIMARY2', 'RDB$11', 10785 'RDB$FOREIGN13', 'RDB$PRIMARY12', 'RDB$FOREIGN18', 'RDB$FOREIGN19', 'RDB$PRIMARY17', 'RDB$INDEX_52', 'RDB$INDEX_44', 10786 'RDB$INDEX_19', 'RDB$INDEX_25', 'RDB$INDEX_14', 'RDB$INDEX_40', 'RDB$INDEX_20', 'RDB$INDEX_26', 'RDB$INDEX_27', 10787 'RDB$INDEX_28', 'RDB$INDEX_23', 'RDB$INDEX_24', 'RDB$INDEX_2', 'RDB$INDEX_36', 'RDB$INDEX_17', 'RDB$INDEX_45', 10788 'RDB$INDEX_16', 'RDB$INDEX_53', 'RDB$INDEX_9', 'RDB$INDEX_10', 'RDB$INDEX_49', 'RDB$INDEX_51', 'RDB$INDEX_11', 10789 'RDB$INDEX_46', 'RDB$INDEX_6', 'RDB$INDEX_31', 'RDB$INDEX_41', 'RDB$INDEX_5', 'RDB$INDEX_47', 'RDB$INDEX_21', 'RDB$INDEX_22', 10790 'RDB$INDEX_18', 'RDB$INDEX_48', 'RDB$INDEX_50', 'RDB$INDEX_13', 'RDB$INDEX_0', 'RDB$INDEX_1', 'RDB$INDEX_12', 'RDB$INDEX_42', 10791 'RDB$INDEX_43', 'RDB$INDEX_15', 'RDB$INDEX_3', 'RDB$INDEX_4', 'RDB$INDEX_39', 'RDB$INDEX_7', 'RDB$INDEX_32', 'RDB$INDEX_38', 10792 'RDB$INDEX_8', 'RDB$INDEX_35', 'RDB$INDEX_37', 'RDB$INDEX_29', 'RDB$INDEX_30', 'RDB$INDEX_33', 'RDB$INDEX_34', 10793 'RDB$FOREIGN21', 'RDB$PRIMARY20', 'RDB$FOREIGN25', 'RDB$FOREIGN26', 'RDB$PRIMARY24', 'RDB$PRIMARY28'] 10794 for index in db.indices: 10795 if index.name.startswith('RDB$'): 10796 self.assertIn(index.name, data) 10797 10798class TestLogParse(FDBTestBase): 10799 def setUp(self): 10800 super(TestLogParse, self).setUp() 10801 def _check_events(self, trace_lines, output): 10802 for obj in log.parse(linesplit_iter(trace_lines)): 10803 self.printout(str(obj)) 10804 self.assertEqual(self.output.getvalue(), output, "Parsed events do not match expected ones") 10805 def test_locale(self): 10806 data = """ 10807 10808SRVDB1 Tue Apr 04 21:25:40 2017 10809 INET/inet_error: read errno = 10054 10810 10811""" 10812 output = """LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 25, 40), message='INET/inet_error: read errno = 10054') 10813""" 10814 locale = getlocale(LC_ALL) 10815 if locale[0] is None: 10816 setlocale(LC_ALL,'') 10817 locale = getlocale(LC_ALL) 10818 try: 10819 self._check_events(data, output) 10820 self.assertEquals(locale, getlocale(LC_ALL), "Locale must not change") 10821 self.clear_output() 10822 if sys.platform == 'win32': 10823 setlocale(LC_ALL, 'Czech_Czech Republic') 10824 else: 10825 setlocale(LC_ALL, 'cs_CZ') 10826 nlocale = getlocale(LC_ALL) 10827 self._check_events(data, output) 10828 self.assertEquals(nlocale, getlocale(LC_ALL), "Locale must not change") 10829 finally: 10830 setlocale(LC_ALL, locale) 10831 def TestWindowsService(self): 10832 data = """ 10833 10834SRVDB1 Tue Apr 04 21:25:40 2017 10835 INET/inet_error: read errno = 10054 10836 10837 10838SRVDB1 Tue Apr 04 21:25:41 2017 10839 Unable to complete network request to host "SRVDB1". 10840 Error reading data from the connection. 10841 10842 10843SRVDB1 Tue Apr 04 21:25:42 2017 10844 INET/inet_error: read errno = 10054 10845 10846 10847SRVDB1 Tue Apr 04 21:25:43 2017 10848 Unable to complete network request to host "SRVDB1". 10849 Error reading data from the connection. 10850 10851 10852SRVDB1 Tue Apr 04 21:28:48 2017 10853 INET/inet_error: read errno = 10054 10854 10855 10856SRVDB1 Tue Apr 04 21:28:50 2017 10857 Unable to complete network request to host "SRVDB1". 10858 Error reading data from the connection. 10859 10860 10861SRVDB1 Tue Apr 04 21:28:51 2017 10862 Sweep is started by SYSDBA 10863 Database "Mydatabase" 10864 OIT 551120654, OAT 551120655, OST 551120655, Next 551121770 10865 10866 10867SRVDB1 Tue Apr 04 21:28:52 2017 10868 INET/inet_error: read errno = 10054 10869 10870 10871SRVDB1 Tue Apr 04 21:28:53 2017 10872 Unable to complete network request to host "SRVDB1". 10873 Error reading data from the connection. 10874 10875 10876SRVDB1 Tue Apr 04 21:28:54 2017 10877 Sweep is finished 10878 Database "Mydatabase" 10879 OIT 551234848, OAT 551234849, OST 551234849, Next 551235006 10880 10881 10882SRVDB1 Tue Apr 04 21:28:55 2017 10883 Sweep is started by SWEEPER 10884 Database "Mydatabase" 10885 OIT 551243753, OAT 551846279, OST 551846279, Next 551846385 10886 10887 10888SRVDB1 Tue Apr 04 21:28:56 2017 10889 INET/inet_error: read errno = 10054 10890 10891 10892SRVDB1 Tue Apr 04 21:28:57 2017 10893 Sweep is finished 10894 Database "Mydatabase" 10895 OIT 551846278, OAT 551976724, OST 551976724, Next 551976730 10896 10897 10898SRVDB1 Tue Apr 04 21:28:58 2017 10899 Unable to complete network request to host "(unknown)". 10900 Error reading data from the connection. 10901 10902 10903SRVDB1 Thu Apr 06 12:52:56 2017 10904 Shutting down the server with 1 active connection(s) to 1 database(s), 0 active service(s) 10905 10906 10907""" 10908 output = """LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 25, 40), message='INET/inet_error: read errno = 10054') 10909LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 25, 41), message='Unable to complete network request to host "SRVDB1".\\nError reading data from the connection.') 10910LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 25, 42), message='INET/inet_error: read errno = 10054') 10911LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 25, 43), message='Unable to complete network request to host "SRVDB1".\\nError reading data from the connection.') 10912LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 28, 48), message='INET/inet_error: read errno = 10054') 10913LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 28, 50), message='Unable to complete network request to host "SRVDB1".\\nError reading data from the connection.') 10914LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 28, 51), message='Sweep is started by SYSDBA\\nDatabase "Mydatabase"\\nOIT 551120654, OAT 551120655, OST 551120655, Next 551121770') 10915LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 28, 52), message='INET/inet_error: read errno = 10054') 10916LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 28, 53), message='Unable to complete network request to host "SRVDB1".\\nError reading data from the connection.') 10917LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 28, 54), message='Sweep is finished\\nDatabase "Mydatabase"\\nOIT 551234848, OAT 551234849, OST 551234849, Next 551235006') 10918LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 28, 55), message='Sweep is started by SWEEPER\\nDatabase "Mydatabase"\\nOIT 551243753, OAT 551846279, OST 551846279, Next 551846385') 10919LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 28, 56), message='INET/inet_error: read errno = 10054') 10920LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 28, 57), message='Sweep is finished\\nDatabase "Mydatabase"\\nOIT 551846278, OAT 551976724, OST 551976724, Next 551976730') 10921LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 4, 21, 28, 58), message='Unable to complete network request to host "(unknown)".\\nError reading data from the connection.') 10922LogEntry(source_id='SRVDB1', timestamp=datetime.datetime(2017, 4, 6, 12, 52, 56), message='Shutting down the server with 1 active connection(s) to 1 database(s), 0 active service(s)') 10923""" 10924 self._check_events(data, output) 10925 def TestLinuxDirect(self): 10926 data = """ 10927MyServer (Client) Fri Apr 6 16:35:46 2018 10928 INET/inet_error: connect errno = 111 10929 10930 10931MyServer (Client) Fri Apr 6 16:51:31 2018 10932 /opt/firebird/bin/fbguard: guardian starting /opt/firebird/bin/fbserver 10933 10934 10935 10936MyServer (Server) Fri Apr 6 16:55:23 2018 10937 activating shadow file /home/db/test_employee.fdb 10938 10939 10940MyServer (Server) Fri Apr 6 16:55:31 2018 10941 Sweep is started by SYSDBA 10942 Database "/home/db/test_employee.fdb" 10943 OIT 1, OAT 0, OST 0, Next 1 10944 10945 10946MyServer (Server) Fri Apr 6 16:55:31 2018 10947 Sweep is finished 10948 Database "/home/db/test_employee.fdb" 10949 OIT 1, OAT 0, OST 0, Next 2 10950 10951 10952MyServer (Client) Fri Apr 6 20:18:52 2018 10953 /opt/firebird/bin/fbguard: /opt/firebird/bin/fbserver normal shutdown. 10954 10955 10956 10957MyServer (Client) Mon Apr 9 08:28:29 2018 10958 /opt/firebird/bin/fbguard: guardian starting /opt/firebird/bin/fbserver 10959 10960 10961 10962MyServer (Server) Tue Apr 17 15:01:27 2018 10963 INET/inet_error: invalid socket in packet_receive errno = 22 10964 10965 10966MyServer (Client) Tue Apr 17 19:42:55 2018 10967 /opt/firebird/bin/fbguard: /opt/firebird/bin/fbserver normal shutdown. 10968 10969 10970 10971""" 10972 output = """LogEntry(source_id='MyServer (Client)', timestamp=datetime.datetime(2018, 4, 6, 16, 35, 46), message='INET/inet_error: connect errno = 111') 10973LogEntry(source_id='MyServer (Client)', timestamp=datetime.datetime(2018, 4, 6, 16, 51, 31), message='/opt/firebird/bin/fbguard: guardian starting /opt/firebird/bin/fbserver') 10974LogEntry(source_id='MyServer (Server)', timestamp=datetime.datetime(2018, 4, 6, 16, 55, 23), message='activating shadow file /home/db/test_employee.fdb') 10975LogEntry(source_id='MyServer (Server)', timestamp=datetime.datetime(2018, 4, 6, 16, 55, 31), message='Sweep is started by SYSDBA\\nDatabase "/home/db/test_employee.fdb"\\nOIT 1, OAT 0, OST 0, Next 1') 10976LogEntry(source_id='MyServer (Server)', timestamp=datetime.datetime(2018, 4, 6, 16, 55, 31), message='Sweep is finished\\nDatabase "/home/db/test_employee.fdb"\\nOIT 1, OAT 0, OST 0, Next 2') 10977LogEntry(source_id='MyServer (Client)', timestamp=datetime.datetime(2018, 4, 6, 20, 18, 52), message='/opt/firebird/bin/fbguard: /opt/firebird/bin/fbserver normal shutdown.') 10978LogEntry(source_id='MyServer (Client)', timestamp=datetime.datetime(2018, 4, 9, 8, 28, 29), message='/opt/firebird/bin/fbguard: guardian starting /opt/firebird/bin/fbserver') 10979LogEntry(source_id='MyServer (Server)', timestamp=datetime.datetime(2018, 4, 17, 15, 1, 27), message='INET/inet_error: invalid socket in packet_receive errno = 22') 10980LogEntry(source_id='MyServer (Client)', timestamp=datetime.datetime(2018, 4, 17, 19, 42, 55), message='/opt/firebird/bin/fbguard: /opt/firebird/bin/fbserver normal shutdown.') 10981""" 10982 self._check_events(data, output) 10983 10984if __name__ == '__main__': 10985 unittest.main() 10986 10987