6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 13:33:07 +01:00

More python tests

This commit is contained in:
Pavel Císař 2021-11-16 19:44:53 +01:00
parent 8858dfd25b
commit 7822a79624
32 changed files with 2251 additions and 1322 deletions

View File

@ -2,14 +2,14 @@
#
# id: bugs.core_2341
# title: Hidden variables conflict with output parameters, causing assertions, unexpected errors or possibly incorrect results
# decription:
# decription:
# tracker_id: CORE-2341
# min_versions: []
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 2.5
# resources: None
@ -23,7 +23,7 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
# test_script_1
#---
# c = db_conn.cursor()
#
#
# cmd = c.prep("""execute block (i varchar(10) = ?) returns (o varchar(10))
# as
# begin
@ -34,7 +34,8 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
# c.execute(cmd,['asd'])
# printData(c)
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """O
----------
@ -42,8 +43,21 @@ asd
"""
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, capsys):
with act_1.db.connect() as con:
c = con.cursor()
cmd = c.prepare("""execute block (i varchar(10) = ?) returns (o varchar(10))
as
begin
o = coalesce(cast(o as date), current_date);
o = i;
suspend;
end""")
c.execute(cmd, ['asd'])
act_1.print_data(c)
#
act_1.expected_stdout = expected_stdout_1
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,25 +2,26 @@
#
# id: bugs.core_2408
# title: isql -ex puts default values of sp parameters before the NOT NULL and COLLATE flags
# decription:
# decription:
# Quote from ticket: "make a procedure with NOT NULL and/or COLLATE flags *and* a default value on any parameter".
# Test enchances this by checking not only procedure but also function and package.
# Also, check is performed for table (I've encountered the same for TABLES definition in some old databases).
#
#
# Algorithm is similar to test for core-5089: we create several DB objects which do have properties from ticket.
# Then we extract metadata and save it into file as 'initial' text.
# After this we drop all objects and make attempt to APPLY just extracted metadata script. It should perform without errors.
# Finally, we extract metadata again and do COMPARISON of their current content and those which are stored 'initial' file.
#
#
# Checked on: WI-V3.0.0.32328 (SS/CS/SC).
#
#
# tracker_id: CORE-2408
# min_versions: ['3.0']
# versions: 3.0
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from difflib import unified_diff
from firebird.qa import db_factory, python_act, Action
# version: 3.0
# resources: None
@ -61,7 +62,7 @@ init_script_1 = """
suspend;
end
^
create or alter function fn_test(
p1 varchar(20) character set utf8 not null collate nums_coll default 'foo'
,p2 dm_test default 'qwe'
@ -134,23 +135,23 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# import subprocess
# import time
# import difflib
#
#
# #-----------------------------------
#
#
# def flush_and_close(file_handle):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# os.fsync(file_handle.fileno())
#
#
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
@ -158,22 +159,22 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# os.remove( f_names_list[i] )
# if os.path.isfile( f_names_list[i]):
# print('ERROR: can not remove file ' + f_names_list[i])
#
#
# #-------------------------------------------
#
#
# db_file=db_conn.database_name
# db_conn.close()
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# f_extract_initial_meta_sql = open( os.path.join(context['temp_directory'],'tmp_meta_2408_init.sql'), 'w')
# subprocess.call( [ context['isql_path'], dsn, "-x", "-ch", "utf8" ],
# stdout = f_extract_initial_meta_sql,
# stderr = subprocess.STDOUT
# )
# flush_and_close( f_extract_initial_meta_sql )
#
#
# ddl_clear_all='''
# drop package pg_test;
# drop function fn_test;
@ -184,85 +185,108 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# drop collation nums_coll;
# commit;
# '''
#
#
# f_meta_drop_all_sql = open( os.path.join(context['temp_directory'],'tmp_meta_2408_drop_all.sql'), 'w')
# f_meta_drop_all_sql.write(ddl_clear_all)
# flush_and_close( f_meta_drop_all_sql )
#
#
# f_meta_drop_all_log = open( os.path.join(context['temp_directory'],'tmp_meta_2408_drop_all.log'), 'w')
# subprocess.call( [ context['isql_path'], dsn, "-i", f_meta_drop_all_sql.name, "-ch", "utf8" ],
# stdout = f_meta_drop_all_log,
# stderr = subprocess.STDOUT
# )
# flush_and_close( f_meta_drop_all_log )
#
#
#
#
# f_apply_extracted_meta_log = open( os.path.join(context['temp_directory'],'tmp_meta_2408_apply.log'), 'w')
# subprocess.call( [ context['isql_path'], dsn, "-i", f_extract_initial_meta_sql.name, "-ch", "utf8" ],
# stdout = f_apply_extracted_meta_log,
# stderr = subprocess.STDOUT
# )
# flush_and_close( f_apply_extracted_meta_log )
#
#
# f_extract_current_meta_sql = open( os.path.join(context['temp_directory'],'tmp_meta_2408_last.sql'), 'w')
# subprocess.call( [ context['isql_path'], dsn, "-x", "-ch", "utf8"],
# stdout = f_extract_current_meta_sql,
# stderr = subprocess.STDOUT
# )
# flush_and_close( f_extract_current_meta_sql )
#
#
#
#
# f_diff_txt=open( os.path.join(context['temp_directory'],'tmp_2408_meta_diff.txt'), 'w')
#
#
# f_old=[]
# f_new=[]
#
#
# f_old.append(f_extract_initial_meta_sql) # tmp_meta_2408_init.sql -- extracted metadata just after 'init_script' was done
# f_new.append(f_extract_current_meta_sql) # tmp_meta_2408_last.sql -- extracted metadata after drop all object and applying 'tmp_meta_2408_init.sql'
#
#
# for i in range(len(f_old)):
# old_file=open(f_old[i].name,'r')
# new_file=open(f_new[i].name,'r')
#
#
# f_diff_txt.write( ''.join( difflib.unified_diff( old_file.readlines(), new_file.readlines() ) ) )
#
#
# old_file.close()
# new_file.close()
#
#
# flush_and_close( f_diff_txt )
#
#
#
#
# # Should be EMPTY:
# ##################
# with open( f_meta_drop_all_log.name, 'r') as f:
# for line in f:
# print( 'Error log of dropping existing objects: ' + f.line() )
#
#
# # Should be EMPTY:
# ##################
# with open( f_apply_extracted_meta_log.name, 'r') as f:
# for line in f:
# print( 'Error log of applying extracted metadata: ' + f.line() )
#
#
# # Should be EMPTY:
# ##################
# with open( f_diff_txt.name,'r') as f:
# for line in f:
# print( ' '.join(line.split()).upper() )
#
#
# ###############################
# # Cleanup.
# time.sleep(1)
# cleanup( [ i.name for i in (f_extract_initial_meta_sql,f_extract_current_meta_sql,f_meta_drop_all_sql,f_meta_drop_all_log,f_apply_extracted_meta_log,f_diff_txt) ] )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
# Extract metadata
act_1.isql(switches=['-x'])
initial_meta = act_1.stdout
# Clear all
ddl_clear_all = '''
drop package pg_test;
drop function fn_test;
drop procedure sp_test;
drop table test;
drop domain dm_test;
drop collation name_coll;
drop collation nums_coll;
commit;
'''
act_1.reset()
act_1.isql(switches=[], input=ddl_clear_all)
# Recreate metadata
act_1.reset()
act_1.isql(switches=[], input=initial_meta)
# Extract metadata again
act_1.reset()
act_1.isql(switches=['-x'])
current_meta = act_1.stdout
# Compare metadata
meta_diff = '\n'.join(unified_diff(initial_meta.splitlines(), current_meta.splitlines()))
assert meta_diff == ''

View File

@ -2,14 +2,15 @@
#
# id: bugs.core_2420
# title: Parsing error in EXECUTE STATEMENT with named parameters
# decription:
# decription:
# tracker_id: CORE-2420
# min_versions: []
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
from firebird.driver import DatabaseError
# version: 2.5
# resources: None
@ -50,16 +51,35 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
# do exit;
# end""")
# print ('Execution OK')
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
expected_stdout_1 = """Execution OK
"""
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
with act_1.db.connect() as con:
c = con.cursor()
# Test fails if next raises an exception
try:
c.execute("""execute block as
declare datedoc date;
declare cod int;
declare num int;
declare name int;
declare summa int;
begin
for execute statement (
' select s.cod,s.num, s.name,sum(g.summa) from sch s
left join getschdet(s.cod,:datedoc ,:datedoc,0,0,0,0,0,0,0,0,0,0,0,1,3) g on 1=1
where s.num in (''50'',''51'') and s.udl<>''У'' and s.root=1
and not exists (select s2.cod from sch s2 where s2.prevcod=s.cod)
group by 1,2,3') (datedoc := :datedoc)
into :cod, :num, :name, :summa
do exit;
end""")
except DatabaseError as exc:
pytest.fail(f"SQL execution failed with: {str(exc)}")

View File

@ -2,14 +2,16 @@
#
# id: bugs.core_2441
# title: Server crashes on UPDATE OR INSERT statement
# decription:
# decription:
# tracker_id: CORE-2441
# min_versions: []
# versions: 2.1.3
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
import datetime
from firebird.qa import db_factory, python_act, Action
from firebird.driver import DatabaseError
# version: 2.1.3
# resources: None
@ -31,14 +33,17 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
# c.execute("""UPDATE OR INSERT INTO TABLE_TXT (FIELD1)
# VALUES (CAST(? AS TIMESTAMP))
# MATCHING(FIELD1)""",[datetime.datetime(2011,5,1)])
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=2.1.3')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
with act_1.db.connect() as con:
c = con.cursor()
c.execute("""UPDATE OR INSERT INTO TABLE_TXT (FIELD1)
VALUES (CAST(? AS TIMESTAMP))
MATCHING(FIELD1)""", [datetime.datetime(2011,5,1)])

View File

@ -4,7 +4,7 @@
# title: External table data not visible to other sessions in Classic
# decription: In 2.1.2 SuperServer, any data written to external tables are visible to other sessions.
# However in Classic, this data is not visible. It seems to be cached and written to file eventually, when this happens it becomes visible.
#
#
# THIS TEST WILL END WITH ERROR IF EXTERNAL TABLE ACCESS IS NOT ALLOWED, WHICH IS BY DEFAULT. It's necessary to adjust firebird.conf.
# tracker_id: CORE-2475
# min_versions: ['2.1.3']
@ -12,16 +12,15 @@
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from pathlib import Path
from firebird.qa import db_factory, python_act, Action, temp_file
# version: 2.1.3
# resources: None
substitutions_1 = []
init_script_1 = """create table EXT1 external file '$(DATABASE_LOCATION)EXT1.TBL'
(PK INTEGER);
"""
init_script_1 = """"""
db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
@ -30,37 +29,45 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
# # init
# import os
# ext_filename = '%sEXT1.TBL' % context[db_path_property]
#
#
# # session A
# c1 = db_conn.cursor()
# c1.execute("insert into EXT1 (PK) values (1)")
#
#
# db_conn.commit()
#
#
# # session B
# con2 = kdb.connect(dsn=dsn,user=user_name,password=user_password)
# c2 = con2.cursor()
# c2.execute('select * from EXT1')
# printData(c2)
#
#
# # cleanup
# con2.close()
# try:
# os.remove(ext_filename)
# except:
# print("Error while removing external table file")
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
expected_stdout_1 = """PK
-----------
1
"""
act_1 = python_act('db_1', substitutions=substitutions_1)
external_table = temp_file('EXT1.TBL')
@pytest.mark.version('>=2.1.3')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, external_table: Path):
# Create external table
act_1.isql(switches=[],
input=f"create table EXT1 external file '{str(external_table)}' (PK INTEGER); exit;")
# session A
with act_1.db.connect() as con:
c = con.cursor()
c.execute("insert into EXT1 (PK) values (1)")
con.commit()
# session B
with act_1.db.connect() as con:
c = con.cursor()
c.execute('select * from EXT1')
result = c.fetchall()
assert result == [(1, )]

View File

@ -2,32 +2,32 @@
#
# id: bugs.core_2477
# title: mon$memory_usage: Sorting memory should be reported as owned by the statement
# decription:
# decription:
# We create view that gathers monitoring info related to all needed levels of statistics (DB, attachment, transaction, call).
# Then this view is "customized" in order to leave only interested info about activity that will be started by separate isql process.
# Then we start ascynchronously ISQL and make it stay in some (small) pause. At this moment we make first "photo" of mon$ info and store
# it in dict object 'map_beg'.
# NB: we should NOT wait too long because when SORT starts it can very fast to fill whole space of TempCacheLimit and mon$memory* counters
# will not change since this poitn at all (===> one mey to get zero difference between mon$ countyers in this case).
#
#
# After small pause (in ISQL connect) will gone, ISQL starts to do "huge sort" by invoking query with 'SELECT DISTINCT FROM <huge data source>'.
# We wait about 1..2 second after this sort start and then make 2nd "photo" of monitoring counters and also store their values in another
# We wait about 1..2 second after this sort start and then make 2nd "photo" of monitoring counters and also store their values in another
# dict object ('map_end').
#
#
# Finally, we force ISQL to finish (by moving DB in full shutdown state) and compare differences between corresp. values of map_end and map_beg.
# Values for DATABASE level (mon$stat_group = 0) change only in SuperServer but never change in CS/SC and remain zero. We do not compare them.
# Values for TRANSACTION level never increase; moreover, mon$memory_allocated counter at the "end-point" (when sorting is running) even is reduced
# (and the reason still remain unknown for me; see letter to dimitr 04-may-2018 20:07).
# So, we compare only difference of mon$memory* counters for ATTACHMENT and STATEMENT level (mon$stat_group = 1 and 3).
#
#
# This difference must be not less than some threshold that depends on FB arch, for __BOTH__ levels (and this is main idea of this test)
# ###################
#
#
# Runs this test on firebird.conf with default TempCacheLimit show following values of differences:
# 1) for SuperServer: ~68.1 Mb;
# 1) for SuperServer: ~68.1 Mb;
# 2) for Classic: ~9.4 Mb
# For this reason minimal threshold for consider difference Ok is about 1 Mb (see MIN_DIFF_THRESHOLD).
#
#
# Checked on (Windows 32 bit):
# 25SC, build 2.5.9.27107: OK, 10.328s.
# 25sS, build 2.5.8.27056: OK, 14.656s.
@ -35,7 +35,10 @@
# 30SS, build 3.0.4.32963: OK, 17.234s.
# 40CS, build 4.0.0.955: OK, 11.219s.
# 40SS, build 4.0.0.967: OK, 12.718s.
#
#
# [pcisar] 16.11.2021
# This test is too complicated and fragile, and it's IMHO not worth to be implemented
#
# tracker_id: CORE-2477
# min_versions: ['2.5.0']
# versions: 2.5
@ -53,7 +56,7 @@ init_script_1 = """
create or alter view v_mon as
select *
from (
select
select
m.mon$stat_group as stat_gr
,rpad( decode(m.mon$stat_group, 0,'0:database', 1,'1:attachment', 2,'2:transaction', 3,'3:statement', 4,'4:call'), 15,' ') as stat_type
,m.mon$memory_used as memo_used
@ -67,24 +70,24 @@ init_script_1 = """
,coalesce( decode( s.mon$state, 0,'finished', 1,'running', 2,'suspended' ), 'n/a') as stm_state
,lower(right( coalesce(trim(coalesce(a.mon$remote_process, a.mon$user)), ''), 20 )) as att_process -- isql.exe or Garbace Collector or Cache Writer
,lower(left( coalesce(cast(s.mon$sql_text as varchar(2000)),''), 50 )) as sql_text
from mon$memory_usage m
from mon$memory_usage m
left join mon$statements s on m.mon$stat_group = 3 and m.mon$stat_id = s.mon$stat_id
left join mon$transactions t on
left join mon$transactions t on
m.mon$stat_group = 2 and m.mon$stat_id = t.mon$stat_id
or m.mon$stat_group = 3 and m.mon$stat_id = s.mon$stat_id and t.mon$transaction_id = s.mon$transaction_id
left join mon$attachments a on
m.mon$stat_group = 1 and m.mon$stat_id = a.mon$stat_id
left join mon$attachments a on
m.mon$stat_group = 1 and m.mon$stat_id = a.mon$stat_id
or m.mon$stat_group=2 and m.mon$stat_id = t.mon$stat_id and a.mon$attachment_id = t.mon$attachment_id
or m.mon$stat_group=3 and m.mon$stat_id = s.mon$stat_id and a.mon$attachment_id = s.mon$attachment_id
where
s.mon$sql_text is null
or
where
s.mon$sql_text is null
or
-- NB: There is additional statement like "SELECT RDB$MAP_USING, RDB$MAP_PLUGIN ..." in 4.0!
-- We have to filter it out and leave here only "our" statement that does SORT job:
s.mon$sql_text containing 'distinct'
) t
where
t.stat_gr = 0
where
t.stat_gr = 0
or
t.att_process similar to '%[\\/]isql(.exe){0,1}'
order by stat_type, stat_id;
@ -98,55 +101,55 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
#
# import os
# import subprocess
# from subprocess import Popen
# import time
# from fdb import services
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# db_file=db_conn.database_name
#
#
# db_conn.close()
#
#
# ISQL_USER=user_name
# ISQL_PSWD=user_password
#
#
# MIN_DIFF_THRESHOLD=1000000
#
#
# # change on True if one need to look at intermediate results of gathering mon$ info
# # (before ISQL async launch; after launch but before starting sort; while sorting)
# RUN_DBG=False
#
#
# DELAY_IN_ISQL_BEFORE_IT_STARTS_SORT = 3
# DELAY_FOR_ISQL_ESTABLISH_ITS_CONNECT = 1
# DELAY_BEFORE_MON_WHILE_SORT_IS_RUNNING = DELAY_IN_ISQL_BEFORE_IT_STARTS_SORT + DELAY_FOR_ISQL_ESTABLISH_ITS_CONNECT + 1
#
#
# SQL_GATHER_SORT_INFO='''
# select
# v.att_process,
# replace(replace(replace(replace(v.sql_text, ascii_char(10),' '), ascii_char(13),' '),' ',' '),' ',' ') as sql_text,
# v.stat_type,
# v.stm_state,
# v.att_id,
# v.trn_id,
# v.sttm_id,
# v.memo_used,
# v.memo_allo,
# v.max_memo_used,
# v.max_memo_allo
# from v_mon v
# select
# v.att_process,
# replace(replace(replace(replace(v.sql_text, ascii_char(10),' '), ascii_char(13),' '),' ',' '),' ',' ') as sql_text,
# v.stat_type,
# v.stm_state,
# v.att_id,
# v.trn_id,
# v.sttm_id,
# v.memo_used,
# v.memo_allo,
# v.max_memo_used,
# v.max_memo_allo
# from v_mon v
# where v.att_id is distinct from current_connection
# '''
#
#
# #--------------------------------------------------------------
#
#
# def result_msg(a_diff_value, a_min_threshold):
# return ( ('OK, expected: increased significantly.') if a_diff_value > a_min_threshold else ('BAD! Did not increased as expected. Difference: ' + "{:d}".format(a_diff_value)+'.') )
#
#
# def debug_store_mon_view(dsn, SQL_GATHER_SORT_INFO, file_name_suffix):
# global os
# global subprocess
@ -157,14 +160,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# subprocess.call( [ context['isql_path'], dsn, '-q', '-n', '-i', f_sql_dbg.name ], stdout=f_log_dbg, stderr = subprocess.STDOUT)
# f_log_dbg.close()
# os.remove(f_sql_dbg.name)
#
#
# def forcely_clean_attachments_by_shutdown_online( db_file ):
#
#
# global RUN_DBG
# global os
#
#
# f_shutdown_log = open( os.path.join(context['temp_directory'],'tmp_shutdown_and_online_2477.log'), 'w')
#
#
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
# "action_properties", "prp_shutdown_mode", "prp_sm_full", "prp_shutdown_db", "0",
# "dbname", db_file,
@ -172,7 +175,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout = f_shutdown_log,
# stderr = subprocess.STDOUT
# )
#
#
# subprocess.call( [context['fbsvcmgr_path'],"localhost:service_mgr",
# "action_db_stats",
# "dbname", db_file, "sts_hdr_pages"
@ -180,7 +183,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout = f_shutdown_log,
# stderr=subprocess.STDOUT
# )
#
#
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
# "action_properties", "prp_db_online",
# "dbname", db_file,
@ -195,16 +198,16 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout = f_shutdown_log,
# stderr=subprocess.STDOUT
# )
#
#
# f_shutdown_log.close()
#
#
# if not RUN_DBG:
# os.remove(f_shutdown_log.name)
#
#
#
#
# #--------------------------------------------------------
#
#
#
#
# sql_text='''
# commit;
# set transaction lock timeout %(DELAY_IN_ISQL_BEFORE_IT_STARTS_SORT)s;
@ -218,15 +221,15 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# on external 'localhost:' || rdb$get_context('SYSTEM','DB_NAME')
# as user '%(ISQL_USER)s' password '%(ISQL_PSWD)s'
# ;
# when any do
# begin
# when any do
# begin
# end
# end
#
# select count(*)
# from (
#
# select count(*)
# from (
# -- this force to use "PLAN SORT":
# select distinct lpad('', 500, uuid_to_char(gen_uuid())) s from rdb$types a,rdb$types b, rdb$types c
# select distinct lpad('', 500, uuid_to_char(gen_uuid())) s from rdb$types a,rdb$types b, rdb$types c
# )
# into c;
# suspend;
@ -234,73 +237,73 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# ^
# set term ;^
# ''' %locals()
#
#
#
#
# f_isql_cmd=open( os.path.join(context['temp_directory'],'tmp_2477_sort.sql'), 'w')
# f_isql_cmd.write(sql_text)
# f_isql_cmd.close()
#
#
# if RUN_DBG:
# debug_store_mon_view(dsn, SQL_GATHER_SORT_INFO, '0')
#
#
#
#
# # Launch async-ly ISQL which must establish connect and:
# # 1) stay in small delay
# # 2) start "big sorting" job (for at least 20-30 seconds):
#
#
# f_log_sort=open( os.path.join(context['temp_directory'], 'tmp_2477_sort.log'), 'w')
# p_sql = subprocess.Popen( [ context['isql_path'], dsn, '-q', '-n', '-i', f_isql_cmd.name ], stdout=f_log_sort, stderr = subprocess.STDOUT)
#
#
# # do NOT remove this delay: we have to wait while ISQL for sure will establish connection.
# ##########################
# time.sleep( DELAY_FOR_ISQL_ESTABLISH_ITS_CONNECT )
#
#
#
#
# if RUN_DBG:
# # NOTE: assign RUN_DBG to True and look in debug snapshot file tmp_c2477_dbg1.log
# # with results of 1st gathering of mon$ info. If it will contain only one record (of DB level)
# # than it means that we have to increase DELAY_FOR_ISQL_ESTABLISH_ITS_CONNECT value):
# debug_store_mon_view(dsn, SQL_GATHER_SORT_INFO, '1')
#
#
#
#
# # Start separate connect for gather monio
# con_mon=fdb.connect(dsn=dsn)
# cur_mon=con_mon.cursor()
#
#
# # Gather info from mon$memory_usage before SORT start (ISQL stays in pause now):
# ###################################
# cur_mon.execute(SQL_GATHER_SORT_INFO)
#
#
# map_beg={}
#
#
# # Take at once all the records that cursor can return (actually it can return only 5 records in 3.0+ SS):
# for x in cur_mon.fetchmanymap(99):
# # we need only several for storing as KEY-VALUE pairs from the whole set of columns of view v_mon:
# (stat_type, att_id, trn_id, sttm_id) = ( v for k,v in x.items() if k in ( 'STAT_TYPE', 'ATT_ID', 'TRN_ID', 'STTM_ID') )
# val = [ v for k,v in x.items() if k in ('MEMO_USED', 'MEMO_ALLO') ]
#
#
# map_beg[ stat_type, att_id, trn_id, sttm_id ] = val
#
#
# #for k,v in sorted(map_beg.items()):
# # print('::: beg ::: k=',k,'; v=',v)
#
#
#
#
# cur_mon.close()
#
#
# # This is mandatory before any subsequent gathering mon$ info:
# con_mon.commit()
#
#
# # This *seems* not necessary but one need to test this again in SC/CS:
# con_mon.close()
# con_mon=fdb.connect(dsn=dsn)
#
#
# # this delay is mandatory and must be greater than delay in ISQL
# # (see 'set tran lock timeout N' in its sql script).
# # We have to give ISQL to actually start SORT job:
# time.sleep( DELAY_BEFORE_MON_WHILE_SORT_IS_RUNNING )
#
#
# cur_mon=con_mon.cursor()
#
#
# # Gather info from mon$memory_usage when SORT is running:
# ###################################
# cur_mon.execute(SQL_GATHER_SORT_INFO)
@ -308,66 +311,66 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# for x in cur_mon.fetchmanymap(99):
# (stat_type, att_id, trn_id, sttm_id) = ( v for k,v in x.items() if k in ( 'STAT_TYPE', 'ATT_ID', 'TRN_ID', 'STTM_ID') )
# val = [ v for k,v in x.items() if k in ('MEMO_USED', 'MEMO_ALLO') ]
#
#
# map_end[ stat_type, att_id, trn_id, sttm_id ] = val
#
#
# cur_mon.close()
#
#
# if RUN_DBG:
# # NOTE: assign RUN_DBG to True and look in debug snapshot file tmp_c2477_dbg1.log
# # with results of 1st gathering of mon$ info.
# debug_store_mon_view(dsn, SQL_GATHER_SORT_INFO, '2')
#
#
# con_mon.close()
#
#
# # We have to be sure that NO ANY activity remains in the database before finish this test.
# # Unfortunately, it seems that just killing process of ISQL (that was launched async-ly) not enough,
# # so we turn database offline and bring back online:
# forcely_clean_attachments_by_shutdown_online( db_file )
#
#
# # ::: !! :::
# ########################################
# # TERMINATE ISQL THAT DOES HUGE SORT JOB
# ########################################
# p_sql.terminate()
# f_log_sort.close()
#
#
# #time.sleep(1)
#
#
# for k,v in sorted(map_beg.items()):
#
#
# if 'database' in k[0]:
# # mon$memory_* counters always ZERO in CS/SC for database level
# pass
#
#
# if 'transaction' in k[0]:
# # mon$memory_* counters never change for transaction level (reason currently is unknown).
# pass
#
#
# if 'attachment' in k[0] or 'statement' in k[0]:
#
#
# (beg_memo_used, beg_memo_allo) = v
#
#
# (end_memo_used, end_memo_allo) = map_end.get(k)
# (dif_memo_used, dif_memo_allo) = (end_memo_used - beg_memo_used, end_memo_allo - beg_memo_allo)
#
#
# #print( k[0].rstrip()+':' )
# # 4debug: output value of mon$memory* counters difference:
# #print( ' '.join( (' * DELTA of mon$memory_used:', "{:9d}".format(dif_memo_used), result_msg(dif_memo_used, MIN_DIFF_THRESHOLD) ) ) )
# #print( ' '.join( (' * DELTA of mon$memory_allo:', "{:9d}".format(dif_memo_allo), result_msg(dif_memo_allo, MIN_DIFF_THRESHOLD) ) ) )
#
#
# print( ' '.join( k[0].split(':') ).rstrip() )
# print( ' * DELTA of mon$memory_used: ' + result_msg(dif_memo_used, MIN_DIFF_THRESHOLD) )
# print( ' * DELTA of mon$memory_allo: ' + result_msg(dif_memo_allo, MIN_DIFF_THRESHOLD) )
#
#
# # cleanup:
# ##########
# time.sleep(1)
# f_list = (f_isql_cmd, f_log_sort)
# for f in f_list:
# os.remove(f.name)
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)

View File

@ -2,61 +2,66 @@
#
# id: bugs.core_2484
# title: Success message when connecting to tiny trash database file
# decription:
# decription:
# We make invalid FDB file by creating binary file and write small data piece to it.
# Then we try to connect to such "database" using ISQL with passing trivial command
# like 'select current_timestamp' for execution.
# ISQL must raise error and quit (obviously without any result to STDOUT).
#
#
# ::: NB :::
# If Windows with non-ascii language is used then message about overlapped IO
# ("-Overlapped I/O operation is in progress") will be translated by OS to localized
# text and it will be displayed in STDERR. This message must be suppressed or ignored.
#
#
# Because of this, it was decided to redirect output of ISQL to logs and open
# them using codecs.open() with errors='ignore' option.
# We check presense of error message in STDERR file created by ISQL.
# It is ennough to verify that STDERR log contains pattern 'SQLSTATE = '.
# Checked on 4.0.0.2164; 3.0.7.33356
#
#
# 02-mar-2021. Re-implemented in order to have ability to run this test on Linux.
#
#
# NOTE: message that clearly points to the reason of failed connection is shown
# only on Linux FB 3.x:
# =====
# Statement failed, SQLSTATE = 08004
# file <...>/tmp_2484_fake.fdb is not a valid database
# =====
#
#
# All other cases produce SQLSTATE = 08001 and somewhat strange after it (from my POV):
# =====
# Windows:
# I/O error during "ReadFile" operation for file "<...>\\TMP_2484_FAKE.FDB"
# -Error while trying to read from file
#
#
# Linux:
# I/O error during "read_retry" operation for file "<...>/tmp_2484_fake.fdb"
# -Error while trying to read from file
# -Success <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< :-)
# =====
#
#
# Checked on:
# * Windows: 4.0.0.2377, 3.0.8.33420 -- both on SS/CS
# * Linux: 4.0.0.2377, 3.0.8.33415
#
#
#
#
# tracker_id: CORE-2484
# min_versions: ['3.0']
# versions: 3.0
# qmid:
# qmid:
import pytest
from firebird.qa import db_factory, isql_act, Action
from pathlib import Path
from firebird.qa import db_factory, python_act, Action, temp_file
# version: 3.0
# resources: None
substitutions_1 = [('SQLSTATE = 08004', 'SQLSTATE = 08001')]
substitutions_1 = [('SQLSTATE = 08004', 'SQLSTATE = 08001'),
('I/O error during.*', ''),
('-File size is less than expected', ''),
('-Error while.*', ''),
('Use CONNECT or CREATE DATABASE to specify a database', '')]
init_script_1 = """"""
@ -64,34 +69,34 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
#
# import os
# import subprocess
# import codecs
# import re
# import time
#
#
# db_conn.close()
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# #--------------------------------------------
#
#
# def flush_and_close( file_handle ):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
@ -102,20 +107,20 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# else:
# print('Unrecognized type of element:', f_names_list[i], ' - can not be treated as file.')
# del_name = None
#
#
# if del_name and os.path.isfile( del_name ):
# os.remove( del_name )
#
#
# #--------------------------------------------
#
#
# f_fake_fdb = open( os.path.join(context['temp_directory'],'tmp_2484_fake.fdb'), 'wb')
# f_fake_fdb.write('ŒåŁä')
# flush_and_close( f_fake_fdb )
#
#
# f_fake_sql = open( os.path.splitext(f_fake_fdb.name)[0]+'.sql', 'w')
# f_fake_sql.write('set heading off; select current_timestamp from rdb$database; quit;')
# flush_and_close( f_fake_sql )
#
#
# f_fake_log = open( os.path.splitext(f_fake_fdb.name)[0]+'.log', 'w')
# f_fake_err = open( os.path.splitext(f_fake_fdb.name)[0]+'.err', 'w')
# subprocess.call( [ context['isql_path'], 'localhost:' + f_fake_fdb.name, "-i", f_fake_sql.name ],
@ -124,7 +129,7 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# )
# flush_and_close( f_fake_log )
# flush_and_close( f_fake_err )
#
#
# ###########################################################################
# # Linux, FB 3.x:
# # Statement failed, SQLSTATE = 08004
@ -133,7 +138,7 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# # Statement failed, SQLSTATE = 08001
# # I/O error during "ReadFile" operation for file "<...>\\TMP_2484_FAKE.FDB"
# # -Error while trying to read from file
#
#
# # Linux, FB 4.x:
# # Statement failed, SQLSTATE = 08001
# # I/O error during "read_retry" operation for file "<...>/tmp_2484_fake.fdb"
@ -145,34 +150,43 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# # -Error while trying to read from file
# # Overlapped I/O operation is in progress << WILL BE IN LOCALIZED FORM!
# ###########################################################################
#
#
# p = re.compile('SQLSTATE\\s+=\\s+',re.IGNORECASE)
# with codecs.open( filename = f_fake_err.name, mode = 'r', errors = 'ignore') as f:
# for line in f:
# if p.search(line):
# print(line)
#
#
# with codecs.open( filename = f_fake_log.name, mode = 'r', errors = 'ignore') as f:
# for line in f:
# if p.search(line):
# print('UNEXPECTED STDOUT: ' + line)
#
#
# # cleanup:
# ##########
# time.sleep(1)
# cleanup( ( f_fake_fdb, f_fake_sql, f_fake_log, f_fake_err ) )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
expected_stdout_1 = """
Statement failed, SQLSTATE = 08001
"""
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stderr_1 = """
Statement failed, SQLSTATE = 08001
"""
fake_db = temp_file('tmp_2484_fake.fdb')
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, fake_db: Path):
fake_db.write_bytes(bytes([1, 2, 3, 4, 5, 6, 0]))
act_1.expected_stdout = ''
act_1.expected_stderr = expected_stderr_1
act_1.isql(switches=['-user', act_1.db.user, '-password', act_1.db.password, str(fake_db)],
connect_db=False,
input='set heading off; select current_timestamp from rdb$database; quit;')
assert act_1.clean_stderr == act_1.clean_expected_stderr
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,59 +2,61 @@
#
# id: bugs.core_2531
# title: The famous "cannot transliterate" error may be thrown when selecting data from the monitoring tables
# decription:
# decription:
# In order to check issues of ticket we have to create Python script which is encoded in non-ascii codepage and also
# its codepage should be NON utf8 (choosed: Windows 1252). This is because all .fbt files have to be encoded only in UTF8,
# so we can not put inside .fbt a statement which contains non-ascii SINGLE-BYTE characters.
#
#
# Character |å|, "LATIN SMALL LETTER A WITH RING ABOVE", was selected in order to verify ticket issue, see:
# http://www.fileformat.info/info/unicode/char/00e5/index.htm
#
#
# Temporary Python file ("tmp_2531_run.py") will contain encoding statement ('# coding: latin-1') followed by commands for:
# 1) make first attachment to database, by Python itself, with charset = Win1252, with preparing: "select 'gång' from rdb$database";
# also, this attachments SAVES string of this query into table (NOTE: it works with charset = win1252);
# 2) make second attachment by ISQL, with charset = utf8, which will query mon$statements.mon$sql_text - this should return query
# which has been prepared by first attachment. This query is compared to that which was stored into table by attachment-1,
# and these rows should be equal: |select 'gång' from rdb$database|
#
#
# Confirmed wrong (incompleted) output of mon$sql_text on 2.1.0.17798 (but there is no "cannot transliterate" error):
# ===
# select 'gång: ' || current_timestamp from rdb$database
# select 'g
# select 'gång: ' || current_timestamp from rdb$database
# select 'g
# ^^^
# |
# +--- three white-spaces here (after 'g')
# ===
# ===
# No such effect on builds >= 2.1.3.18185.
#
#
# Refactored 08-may-2017: replaced buggy "folder.replace()" with bulk of backslashes ("") with locals() usage.
# Checked again on Classic for: WI-V3.0.2.32708, WI-T4.0.0.633
# Checked again on Classic for: WI-V3.0.2.32708, WI-T4.0.0.633
# (added expression to WHERE-block to filter out record from mon$statements with RDB$AUTH_MAPPING data).
#
#
# 02-MAR-2021:
# Changed code in order to remove dependency on PATH-list (CLI utilities must be invoked using context['..._path'])
# Full path+name of FB client library file is passed to generated Python code.
# Removed unneeded variables.
#
#
# Checked on Windows: 4.0.0.2377 (SS/CS), 3.0.8.33420 (SS/CS), 2.5.9.27152 (SC)
# Checked on Linux: 4.0.0.2377, 3.0.8.33415.
#
#
# tracker_id: CORE-2531
# min_versions: ['2.5.0']
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 2.5
# resources: None
substitutions_1 = [('SQL_TEXT_BLOB_ID .*', ''), ('[\t ]+', ' ')]
init_script_1 = """"""
init_script_1 = """
recreate table non_ascii(stored_sql_expr varchar(255) character set win1252);
"""
db_1 = db_factory(sql_dialect=3, init=init_script_1)
db_1 = db_factory(sql_dialect=3, init=init_script_1, charset='WIN1252')
# test_script_1
#---
@ -64,18 +66,16 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# import time
# import codecs
# from fdb import services
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
# engine = db_conn.engine_version
# db_conn.close()
#
#
# svc = services.connect()
# FB_HOME = os.path.normpath( svc.get_home_directory() ) # 'c:
# irebird' --> 'c:
# irebird' (i.e. remove trailing backslash if needed)
# FB_HOME = os.path.normpath( svc.get_home_directory() ) # 'c:\\firebird\\' --> 'c:\\firebird' (i.e. remove trailing backslash if needed)
# svc.close()
#
#
# FB_CLNT = '<UNKNOWN>'
# if os.name == 'nt':
# # For Windows we assume that client library is always in FB_HOME dir:
@ -87,24 +87,24 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# # For Linux client library will be searched in 'lib' subdirectory of FB_HOME:
# # con=fdb.connect( dsn='localhost:employee', fb_library_name='/var/tmp/fb40tmp/lib/libfbclient.so', ...)
# FB_CLNT=os.path.join(FB_HOME, 'lib', 'libfbclient.so' )
#
#
# #--------------------------------------------
#
#
# def flush_and_close( file_handle ):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb'):
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
@ -115,19 +115,19 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# else:
# print('Unrecognized type of element:', f_names_list[i], ' - can not be treated as file.')
# del_name = None
#
#
# if del_name and os.path.isfile( del_name ):
# os.remove( del_name )
#
#
# #--------------------------------------------
#
#
# #non_ascii_query="select 'gång' from rdb$database"
# non_ascii_query=u"select 'gång' as non_ascii_literal from rdb$database"
#
#
# f_sql_txt='''
# set count on;
# set blob all;
# set list on;
# set list on;
# select stored_sql_expr from non_ascii;
# select
# c.rdb$character_set_name as connection_charset
@ -140,14 +140,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# and s.mon$sql_text containing 'non_ascii_literal'
# ;
# '''
#
#
# f_mon_sql = open( os.path.join(context['temp_directory'], 'tmp_2531_w1252.sql'), 'w' )
# f_mon_sql.write(f_sql_txt)
# flush_and_close( f_mon_sql )
#
#
# isql_path = context['isql_path']
# isql_file = f_mon_sql.name
#
#
# ######################################################################
# ### t e m p o r a r y P y t h o n s c r i p t s t ar t ###
# ######################################################################
@ -157,57 +157,58 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# import subprocess
# os.environ["ISC_USER"] = '%(user_name)s'
# os.environ["ISC_PASSWORD"] = '%(user_password)s'
#
#
# att1 = fdb.connect(dsn = r'%(dsn)s', fb_library_name = r'%(FB_CLNT)s', charset = 'win1252')
# att1.execute_immediate("recreate table non_ascii(stored_sql_expr varchar(255) character set win1252)")
# att1.commit()
#
#
# txt = "%(non_ascii_query)s"
#
#
# cur1=att1.cursor()
# cur1.execute( "insert into non_ascii(stored_sql_expr) values('%%s')" %% txt.replace("'","''") )
# att1.commit()
#
#
# # The will cause SQL expression with non-ascii character
# # appear in mon$statements.mon$sql_text column.
# # NOTE: charset of current connection is >>> win1252 <<<
# cur1.prep(txt)
#
#
# subprocess.call([ r'%(isql_path)s', r'%(dsn)s', '-ch', 'utf8', '-i', r'%(isql_file)s' ])
#
#
# cur1.close()
# att1.commit()
# att1.close()
# ''' % dict(globals(), **locals())
# ############## temporary Python script finish ###################
#
#
#
#
# #####################################################################
# ### Create temporary Python script with code page = Windows-1252, ###
# ### so |select 'gång' from rdb$database| will be written there in ###
# ### single-byte encoding rather than in utf8. ###
# ### single-byte encoding rather than in utf8. ###
# ####################################################################
# f_python_run=codecs.open( os.path.join(context['temp_directory'],'tmp_2531_w1252.py'), encoding='cp1252', mode='w')
# f_python_run.write(f_python_txt)
#
#
# flush_and_close( f_python_run )
# time.sleep(1)
#
#
# runProgram( sys.executable, [f_python_run.name] )
#
#
# # 02.03.2021 DO NOT! subprocess.call( [sys.executable, f_python_run.name] ) -- for unknown reason this will NOT issu anything to STDOUT!
#
#
# time.sleep(1)
#
#
# # 02.03.2021: do NOT pass to cleanup() files!
# # It will fail with 'uknown type' for executed script ('f_python_run')
# # because it will consider its type as 'instance' rather than common 'file'!
# # We have to pass only NAMES list of used files here:
# cleanup( [i.name for i in (f_python_run,f_mon_sql)] )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
STORED_SQL_EXPR select 'gång' as non_ascii_literal from rdb$database
@ -218,8 +219,32 @@ expected_stdout_1 = """
"""
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
non_ascii_query = "select 'gång' as non_ascii_literal from rdb$database"
non_ascii_query_inline = non_ascii_query.replace("'","''")
script = '''
set count on;
set blob all;
set list on;
select stored_sql_expr from non_ascii;
select
c.rdb$character_set_name as connection_charset
,s.mon$sql_text as sql_text_blob_id
from mon$attachments a
left join rdb$character_sets c on a.mon$character_set_id = c.rdb$character_set_id
left join mon$statements s on a.mon$attachment_id = s.mon$attachment_id
where
s.mon$attachment_id <> current_connection
and s.mon$sql_text containing 'non_ascii_literal'
;
'''
act_1.expected_stdout = expected_stdout_1
with act_1.db.connect(charset='WIN1252') as con:
c = con.cursor()
c.execute(f"insert into non_ascii(stored_sql_expr) values('{non_ascii_query_inline}')")
con.commit()
x = c.prepare(non_ascii_query)
act_1.isql(switches=[], input=script, charset='WIN1252')
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,14 +2,14 @@
#
# id: bugs.core_2573
# title: The server crashes when selecting from the MON$ tables in the ON DISCONNECT trigger
# decription:
# decription:
# tracker_id: CORE-2573
# min_versions: []
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 2.5
# resources: None
@ -30,24 +30,39 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
# select mon$stat_id from mon$attachments rows 1 into :i;
# end
# """
#
#
# c = db_conn.cursor()
# c.execute(sql)
# db_conn.commit()
# db_conn.close()
#
#
# db_conn = kdb.connect(dsn=dsn,user=user_name,password=user_password)
# c = db_conn.cursor()
# c.execute("DROP TRIGGER DIST")
# db_conn.commit()
# db_conn.close()
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
sql = """CREATE OR ALTER TRIGGER DIST
ON DISCONNECT POSITION 0
AS
declare variable i integer;
begin
select mon$stat_id from mon$attachments rows 1 into :i;
end
"""
with act_1.db.connect() as con:
c = con.cursor()
c.execute(sql)
con.commit()
# The server should could be crashed at this point
with act_1.db.connect() as con:
c = con.cursor()
c.execute('DROP TRIGGER DIST')
con.commit()

View File

@ -2,7 +2,7 @@
#
# id: bugs.core_2602
# title: Attachments using NONE charset may cause reads from MON$ tables to fail
# decription:
# decription:
# Fully refactored 05-feb-2018. Apply HASH() functions to unicode mon$sql_text in order to returnonly numeric value
# rather than non-translatable unicode representation which can differ on machines with different codepage / OS.
# For example, instead of (on Win XP with codepage 1251):
@ -16,7 +16,7 @@
# - lock conflict on no wait transaction', -901, 335544345)
# - just after issued 1st cursor result.
# No error since 2.5.0.26074.
#
#
# 25.12.2019: added filtering expr to WHERE clause in order to prevent from passing through records related to RDB$AUTH table (4.x).
# Last tested 25.12.2019 on:
# 4.0.0.1707 SS: 1.448s.
@ -27,14 +27,14 @@
# 3.0.5.33212 CS: 1.755s.
# 2.5.9.27149 SC: 0.218s.
# 2.5.9.27119 SS: 2.411s.
#
#
# tracker_id: CORE-2602
# min_versions: ['2.5']
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 2.5
# resources: None
@ -47,34 +47,34 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
#
# import os
# import fdb
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# db_conn.close()
#
#
# c1none=fdb.connect(dsn=dsn,charset='none')
# c1utf8=fdb.connect(dsn=dsn,charset='utf8')
#
#
# c2none=fdb.connect(dsn=dsn,charset='none')
# c2utf8=fdb.connect(dsn=dsn,charset='utf8')
#
#
# r1none = c1none.cursor()
# r1utf8 = c1utf8.cursor()
#
#
# r2none = c2none.cursor()
# r2utf8 = c2utf8.cursor()
#
#
# # In attachment with charset = NONE we start query to mon$database which includes two non-ascii characters:
# # 1) Unicode Character 'LATIN SMALL LETTER A WITH ACUTE' (U+00E1)
# # 1) Unicode Character 'LATIN SMALL LETTER A WITH ACUTE' (U+00E1)
# # 2) Unicode Character 'LATIN SMALL LETTER E WITH ACUTE' (U+00E9)
# r1none.execute("select '123áé456' from mon$database")
#
#
# sql='''
# select
# iif(s.mon$attachment_id = current_connection, 'this', 'othr') as attach
# select
# iif(s.mon$attachment_id = current_connection, 'this', 'othr') as attach
# -- do NOT return SQL text of query with non-ascii characters: it can be displayed differently
# -- depending on machine codepage (or OS?):
# -- >>> disabled 05-feb-2018 >>> , iif(s.mon$sql_text like '%123%456%', s.mon$sql_text, '') as sql_text
@ -85,49 +85,50 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# join mon$attachments a on s.mon$attachment_id = a.mon$attachment_id
# join rdb$character_sets c on a.mon$character_set_id = c.rdb$character_set_id
# where
# s.mon$attachment_id != current_connection
# s.mon$attachment_id != current_connection
# and s.mon$sql_text NOT containing 'mon$statements'
# and s.mon$sql_text NOT containing 'rdb$auth'
# and a.mon$remote_protocol is not null
# '''
#
#
# r2none.execute(sql)
# for r in r2none:
# #print( ' '.join( 'THIS connect with charset NONE. OTHER connect tiwh charset UTF8.', 'WE see other sqltest hash as: ', r[0], '; sql_text_hash: ', str( r[1] ), '; charset_name', r[2] ) )
# #print('r2none',r)
# print( ' '.join( ( 'Attach: r2none.', r[0], '; sql_text_hash: ', str( r[1] ), '; charset_name', r[2] ) ) )
#
#
# r2utf8.execute(sql)
# for r in r2utf8:
# print( ' '.join( ( 'Attach: r2utf8.', r[0], '; sql_text_hash: ', str( r[1] ), '; charset_name', r[2] ) ) )
# #print('r2utf8',r)
#
#
# c1none.close()
# #----------------------------
#
#
# r1utf8.execute("select '123áé456' from mon$database")
#
#
# c2none.commit()
# c2utf8.commit()
#
#
# r2none.execute(sql)
# for r in r2none:
# #print('r2none', r)
# print( ' '.join( ( 'Attach: r2none.', r[0], '; sql_text_hash: ', str( r[1] ), '; charset_name', r[2] ) ) )
#
#
# r2utf8.execute(sql)
# for r in r2utf8:
# #print('r2utf8', r)
# print( ' '.join( ( 'Attach: r2utf8.', r[0], '; sql_text_hash: ', str( r[1] ), '; charset_name', r[2] ) ) )
#
#
# c1utf8.close()
# #---------------------------
#
#
# c2none.close()
# c2utf8.close()
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
Attach: r2none. othr ; sql_text_hash: 98490476833044645 ; charset_name NONE
@ -137,8 +138,57 @@ expected_stdout_1 = """
"""
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, capsys):
with act_1.db.connect(charset='UTF8') as con1_utf8, \
act_1.db.connect(charset='NONE') as con2_none, \
act_1.db.connect(charset='UTF8') as con2_utf8:
with act_1.db.connect(charset='NONE') as con1_none:
r1none = con1_none.cursor()
r1utf8 = con1_utf8.cursor()
r2none = con2_none.cursor()
r2utf8 = con2_utf8.cursor()
# In attachment with charset = NONE we start query to mon$database which includes two non-ascii characters:
# 1) Unicode Character 'LATIN SMALL LETTER A WITH ACUTE' (U+00E1)
# 2) Unicode Character 'LATIN SMALL LETTER E WITH ACUTE' (U+00E9)
r1none.execute("select '123áé456' from mon$database")
sql = '''
select
iif(s.mon$attachment_id = current_connection, 'this', 'othr') as attach
-- do NOT return SQL text of query with non-ascii characters: it can be displayed differently
-- depending on machine codepage (or OS?):
-- >>> disabled 05-feb-2018 >>> , iif(s.mon$sql_text like '%123%456%', s.mon$sql_text, '') as sql_text
-- Use HASH(sql_text) instead. Bug (in 2.1.3) still can be reproduces with hash() also:
,hash(s.mon$sql_text) as sql_text_hash
,trim(c.rdb$character_set_name) as charset_name
from mon$statements s
join mon$attachments a on s.mon$attachment_id = a.mon$attachment_id
join rdb$character_sets c on a.mon$character_set_id = c.rdb$character_set_id
where
s.mon$attachment_id != current_connection
and s.mon$sql_text NOT containing 'mon$statements'
and s.mon$sql_text NOT containing 'rdb$auth'
and a.mon$remote_protocol is not null
'''
r2none.execute(sql)
for r in r2none:
print(' '.join(('Attach: r2none.', r[0], '; sql_text_hash: ', str(r[1]), '; charset_name', r[2])))
r2utf8.execute(sql)
for r in r2utf8:
print(' '.join(('Attach: r2utf8.', r[0], '; sql_text_hash: ', str(r[1]), '; charset_name', r[2])))
r1utf8.execute("select '123áé456' from mon$database")
con2_none.commit()
con2_utf8.commit()
r2none.execute(sql)
for r in r2none:
print(' '.join(('Attach: r2none.', r[0], '; sql_text_hash: ', str(r[1]), '; charset_name', r[2])))
r2utf8.execute(sql)
for r in r2utf8:
print(' '.join(('Attach: r2utf8.', r[0], '; sql_text_hash: ', str(r[1]), '; charset_name', r[2])))
#
act_1.expected_stdout = expected_stdout_1
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,14 +2,14 @@
#
# id: bugs.core_2606
# title: Multibyte CHAR value requested as VARCHAR is returned with padded spaces
# decription:
# decription:
# tracker_id: CORE-2606
# min_versions: ['3.0']
# versions: 3.0
# qmid:
# qmid:
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 3.0
# resources: None
@ -22,57 +22,89 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
#
# import os
#
#
# db_conn.close()
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# sql_cmd='''
# set list on;
#
#
# select s.rdb$character_set_name as client_charset
# from mon$attachments a
# join rdb$character_sets s on a.mon$character_set_id = s.rdb$character_set_id
# from mon$attachments a
# join rdb$character_sets s on a.mon$character_set_id = s.rdb$character_set_id
# where a.mon$attachment_id=current_connection;
#
#
# --set sqlda_display on;
# --set planonly;
# --set echo on;
#
#
# select cast('A' as char character set utf8) || '.' as char1_utf8 from rdb$database;
# select cast('A' as varchar(1) character set utf8) || '.' as varc1_utf8 from rdb$database;
# select cast('A' as char character set ascii) || '.' char1_ascii from rdb$database;
# select cast('A' as varchar(1) character set ascii) || '.' varc1_ascii from rdb$database;
# '''
#
#
# # Wrong result was encountered only in FB 1.5.6, for cast('A' as Char charset utf8 / ascii), on any client charset.
# # Varchar always returns expected output.
#
#
# runProgram('isql',['-q', '-ch', 'UTF8', dsn], sql_cmd)
# runProgram('isql',['-q', '-ch', 'SJIS_0208', dsn], sql_cmd)
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
expected_stdout_1 = """
act_1 = python_act('db_1', substitutions=substitutions_1)
test_script_1 = """
set list on;
select s.rdb$character_set_name as client_charset
from mon$attachments a
join rdb$character_sets s on a.mon$character_set_id = s.rdb$character_set_id
where a.mon$attachment_id=current_connection;
--set sqlda_display on;
--set planonly;
--set echo on;
select cast('A' as char character set utf8) || '.' as char1_utf8 from rdb$database;
select cast('A' as varchar(1) character set utf8) || '.' as varc1_utf8 from rdb$database;
select cast('A' as char character set ascii) || '.' char1_ascii from rdb$database;
select cast('A' as varchar(1) character set ascii) || '.' varc1_ascii from rdb$database;
"""
expected_stdout_1_a = """
CLIENT_CHARSET UTF8
CHAR1_UTF8 A.
VARC1_UTF8 A.
CHAR1_ASCII A.
VARC1_ASCII A.
"""
expected_stdout_1_b = """
CLIENT_CHARSET SJIS_0208
CHAR1_UTF8 A.
VARC1_UTF8 A.
CHAR1_ASCII A.
VARC1_ASCII A.
"""
"""
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
act_1.expected_stdout = expected_stdout_1_a
act_1.script = test_script_1
act_1.charset = 'UTF8'
act_1.execute()
assert act_1.clean_stdout == act_1.clean_expected_stdout
act_1.reset()
act_1.expected_stdout = expected_stdout_1_b
act_1.script = test_script_1
act_1.charset = 'SJIS_0208'
act_1.execute()
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -9,7 +9,7 @@
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 2.5
# resources: None
@ -25,26 +25,37 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# c = db_conn.cursor()
# con2 = kdb.connect(dsn=dsn,user=user_name,password=user_password)
# c2 = con2.cursor()
#
#
# c.execute("select _dos850 '123áé456' from rdb$database")
# c2.execute("select mon$sql_text from mon$statements s where s.mon$sql_text containing '_dos850'")
# #printData(c2)
# for r in c2:
# print(r[0])
#
#
# con2.close()
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
select mon$sql_text from mon$statements s where s.mon$sql_text containing '_dos850'
select _dos850 X'313233C3A1C3A9343536' from rdb$database
"""
"""
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, capsys):
act_1.expected_stdout = expected_stdout_1
with act_1.db.connect() as con1:
c1 = con.cursor()
with act_1.db.connect() as con2:
c2 = con.cursor()
c1.execute("select _dos850 '123áé456' from rdb$database")
c2.execute("select mon$sql_text from mon$statements s where s.mon$sql_text containing '_dos850'")
for r in c2:
print(r[0])
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,19 +2,20 @@
#
# id: bugs.core_2635
# title: Unique index with a lot of NULL keys can be corrupted at level 1
# decription:
# decription:
# tracker_id: CORE-2635
# min_versions: ['2.1.4', '2.0.6', '2.5']
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 2.5
# resources: None
substitutions_1 = []
substitutions_1 = [('[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]', ''),
('Relation [0-9]{3,4}', 'Relation')]
init_script_1 = """set term ^;
recreate table t (id int, sss varchar(255)) ^
@ -61,12 +62,25 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
# db_conn.close()
# runProgram('gfix',['-validate','-full','-no_update','-user',user_name,'-password',user_password,dsn])
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
Validation started
Relation (T)
process pointer page 0 of 1
Index 1 (T_ID_DESC)
Index 2 (T_ID_ASC)
Index 3 (T_ID_SSS_DESC)
Index 4 (T_ID_SSS_ASC)
Relation (T) is ok
Validation finished
"""
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
act_1.expected_stdout = expected_stdout_1
with act_1.connect_server() as srv:
srv.database.validate(database=str(act_1.db.db_path))
act_1.stdout = '\n'.join(srv.readlines())
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,14 +2,14 @@
#
# id: bugs.core_2651
# title: Incorrect "string right truncation" error with NONE column and multibyte connection charset
# decription:
# decription:
# tracker_id: CORE-2651
# min_versions: []
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 2.5
# resources: None
@ -35,12 +35,16 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
# finally:
# con.close()
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
with act_1.db.connect(charset='CP943C') as con:
c = con.cursor()
try:
c.execute("select * from TEST_NONE")
except:
pytest.fail("Test FAILED")

View File

@ -2,18 +2,18 @@
#
# id: bugs.core_2668
# title: Write note into log when automatic sweep is started
# decription:
# decription:
# In order to make database be 'ready' for sweep auto-start we:
# 1. Launch ISQL in async. process (using Python subprocess.Popen() unit) which does:
# 1.1. Change DB sweep interval to small value (100 selected).
# 1.2. Create table and add one row in it (marked as 'LOCKED_FOR_PAUSE') + COMMIT.
# 1.3. Start EXECUTE BLOCK with adding 150 of rows in autonomous transactions
# 1.3. Start EXECUTE BLOCK with adding 150 of rows in autonomous transactions
# (this lead eventually to difference Next - OIT =~ 150).
# 1.4. Run execute block with ES/EDS which will establish new attachment (we specify
# there connection ROLE as some non-existent string, see ":v_role" usage below).
# This EB will try to UPDATE record which is LOCKED now by 1st ("main") attachment.
# ISQL will infinitelly hang since this moment.
#
#
# 2. Run (in main Python thread) FBSVCMGR with:
# 2.1. Moving database to SHUTDOWN state;
# 2.2. Returning database back to ONLINE.
@ -22,20 +22,26 @@
# 2.5. Take small delay (~2..3 seconds) in order to allow OS to finish writing new messages
# about SWEEP auto-start in firebird.log.
# 2.6. Obtaining content of firebird.log and storing it in separate file ('f_fblog_after').
#
#
# 3. Compare two files: f_fblog_before and f_fblog_after (using Python package "diff").
# Checked on:
# 4.0.0.2173 SS/SC/CS
# 3.0.7.33357 SS/SC/CS
# 2.5.9.27152 SS/SC/CS
#
#
# tracker_id: CORE-2668
# min_versions: ['2.5.2']
# versions: 2.5.2
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
import time
import subprocess
import re
from pathlib import Path
from difflib import unified_diff
from firebird.qa import db_factory, python_act, Action, temp_file
from firebird.driver import DbWriteMode, ShutdownMode, ShutdownMethod
# version: 2.5.2
# resources: None
@ -56,16 +62,16 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# import difflib
# import shutil
# import re
#
#
# def svc_get_fb_log( engine, f_fb_log ):
#
#
# import subprocess
#
#
# if engine.startswith('2.5'):
# get_firebird_log_key='action_get_ib_log'
# else:
# get_firebird_log_key='action_get_fb_log'
#
#
# subprocess.call([ context['fbsvcmgr_path'],
# "localhost:service_mgr",
# get_firebird_log_key
@ -73,32 +79,32 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout=f_fb_log, stderr=subprocess.STDOUT
# )
# return
#
#
# engine = str(db_conn.engine_version)
# db_file=db_conn.database_name
#
#
# db_conn.close()
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# #---------------------------------------------
#
#
# def flush_and_close(file_handle):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb'):
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
@ -106,11 +112,11 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# os.remove( f_names_list[i] )
# if os.path.isfile( f_names_list[i]):
# print('ERROR: can not remove file ' + f_names_list[i])
#
#
# #--------------------------------------------
#
#
# f_init_log = open( os.path.join(context['temp_directory'],'tmp_init_2668.log'), 'w')
#
#
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
# "action_properties", "prp_sweep_interval", "100",
# "dbname", db_file,
@ -118,40 +124,40 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout = f_init_log,
# stderr = subprocess.STDOUT
# )
#
#
# subprocess.call([ context['fbsvcmgr_path'], "localhost:service_mgr",
# "action_properties", "prp_write_mode", "prp_wm_async",
# "dbname", db_file ],
# stdout = f_init_log,
# stderr = subprocess.STDOUT
# )
#
#
# f_work_sql=open( os.path.join(context['temp_directory'],'tmp_work_2668.sql'), 'w')
#
#
# sql_dml='''
# recreate table test(s varchar(36) unique);
# insert into test(s) values('LOCKED_FOR_PAUSE');
# commit;
#
#
# set transaction read committed WAIT;
#
#
# update test set s = s where s = 'LOCKED_FOR_PAUSE';
#
#
# set term ^;
# execute block as
# declare n int = 150;
# declare v_role varchar(31);
# begin
# while (n > 0) do
# in autonomous transaction do
# insert into test(s) values( rpad('', 36, uuid_to_char(gen_uuid()) ) )
# while (n > 0) do
# in autonomous transaction do
# insert into test(s) values( rpad('', 36, uuid_to_char(gen_uuid()) ) )
# returning :n-1 into n;
#
#
# v_role = left(replace( uuid_to_char(gen_uuid()), '-', ''), 31);
#
#
# begin
# execute statement ('update test set s = s where s = ?') ('LOCKED_FOR_PAUSE')
# on external
# on external
# 'localhost:' || rdb$get_context('SYSTEM', 'DB_NAME')
# as user 'SYSDBA' password 'masterkey' role v_role
# with autonomous transaction;
@ -159,7 +165,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# begin
# end
# end
#
#
# end
# ^
# set term ;^
@ -168,12 +174,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# '''
# f_work_sql.write(sql_dml)
# flush_and_close( f_work_sql )
#
#
# f_work_log=open( os.path.join(context['temp_directory'],'tmp_work_2668.log'), 'w')
#
#
# p_work_sql=Popen( [context['isql_path'], dsn, "-i", f_work_sql.name], stdout = f_work_log, stderr = subprocess.STDOUT )
# time.sleep(3)
#
#
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
# "action_properties", "prp_shutdown_mode", "prp_sm_full", "prp_shutdown_db", "0",
# "dbname", db_file,
@ -181,11 +187,11 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout = f_init_log,
# stderr = subprocess.STDOUT
# )
#
#
#
#
# p_work_sql.terminate()
# flush_and_close( f_work_log )
#
#
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
# "action_properties", "prp_db_online",
# "dbname", db_file,
@ -193,75 +199,137 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout = f_init_log,
# stderr = subprocess.STDOUT
# )
#
#
# flush_and_close( f_init_log )
#
#
# # 4 debug only -- shutil.copy2(db_file, os.path.splitext(db_file)[0]+'.copy.fdb')
#
#
# f_fblog_before=open( os.path.join(context['temp_directory'],'tmp_2668_fblog_before.txt'), 'w')
# svc_get_fb_log( engine, f_fblog_before )
# flush_and_close( f_fblog_before )
#
#
# ###########################################
# # Make connection to database.
# # SWEEP should be auto started at this point:
# ###########################################
#
#
# con_for_sweep_start=fdb.connect(dsn = dsn)
#
#
# # NOTE: it is mandatory to start transaction for auto-sweep:
# con_for_sweep_start.begin()
#
#
# # _!_!_!_!_!_!_!_!_!_! do NOT reduce this delay: firebird.log get new messages NOT instantly !_!_!_!_!_!_!_!_
# # Currently firebird.log can stay with OLD content if heavy concurrent workload exists on the same host!
# time.sleep(2)
#
#
# con_for_sweep_start.close()
#
#
# f_fblog_after=open( os.path.join(context['temp_directory'],'tmp_2668_fblog_after.txt'), 'w')
# svc_get_fb_log( engine, f_fblog_after )
# flush_and_close( f_fblog_after )
#
#
# oldfb=open(f_fblog_before.name, 'r')
# newfb=open(f_fblog_after.name, 'r')
#
#
# difftext = ''.join(difflib.unified_diff(
# oldfb.readlines(),
# oldfb.readlines(),
# newfb.readlines()
# ))
# oldfb.close()
# newfb.close()
#
#
# f_diff_txt=open( os.path.join(context['temp_directory'],'tmp_2668_diff.txt'), 'w')
# f_diff_txt.write(difftext)
# flush_and_close( f_diff_txt )
#
#
# pattern = re.compile('Sweep\\s+.*SWEEPER', re.IGNORECASE)
#
# # NB: difflib.unified_diff() can show line(s) that present in both files, without marking that line(s) with "+".
#
# # NB: difflib.unified_diff() can show line(s) that present in both files, without marking that line(s) with "+".
# # Usually these are 1-2 lines that placed just BEFORE difference starts.
# # So we have to check output before display diff content: lines that are really differ must start with "+".
#
#
# with open( f_diff_txt.name,'r') as f:
# for line in f:
# if line.startswith('+') and pattern.search(line):
# print('Expected line FOUND.')
#
#
# ###############################
# # Cleanup.
# time.sleep(1)
# cleanup( [x.name for x in (f_init_log,f_work_sql,f_work_log,f_fblog_before,f_fblog_after,f_diff_txt) ] )
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
Expected line FOUND.
"""
"""
work_script_1 = temp_file('work_script.sql')
@pytest.mark.version('>=2.5.2')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, work_script_1: Path):
work_script_1.write_text('''
recreate table test(s varchar(36) unique);
insert into test(s) values('LOCKED_FOR_PAUSE');
commit;
set transaction read committed WAIT;
update test set s = s where s = 'LOCKED_FOR_PAUSE';
set term ^;
execute block as
declare n int = 150;
declare v_role varchar(31);
begin
while (n > 0) do
in autonomous transaction do
insert into test(s) values( rpad('', 36, uuid_to_char(gen_uuid()) ) )
returning :n-1 into n;
v_role = left(replace( uuid_to_char(gen_uuid()), '-', ''), 31);
begin
execute statement ('update test set s = s where s = ?') ('LOCKED_FOR_PAUSE')
on external
'localhost:' || rdb$get_context('SYSTEM', 'DB_NAME')
as user 'SYSDBA' password 'masterkey' role v_role
with autonomous transaction;
when any do
begin
end
end
end
^
set term ;^
set heading off;
select '-- shutdown me now --' from rdb$database;
''')
with act_1.connect_server() as srv:
srv.database.set_sweep_interval(database=str(act_1.db.db_path), interval=100)
srv.database.set_write_mode(database=str(act_1.db.db_path), mode=DbWriteMode.ASYNC)
p_work_sql = subprocess.Popen([act_1.vars['isql'], '-i', str(work_script_1),
'-user', act_1.db.user,
'-password', act_1.db.password, act_1.db.dsn],
stderr = subprocess.STDOUT)
time.sleep(3)
srv.database.shutdown(database=str(act_1.db.db_path), mode=ShutdownMode.FULL,
method=ShutdownMethod.FORCED, timeout=0)
p_work_sql.terminate()
srv.database.bring_online(database=str(act_1.db.db_path))
srv.info.get_log()
fblog_before = srv.readlines()
with act_1.db.connect() as con_for_sweep_start:
con_for_sweep_start.begin()
time.sleep(2)
srv.info.get_log()
fblog_after = srv.readlines()
pattern = re.compile('Sweep\\s+.*SWEEPER', re.IGNORECASE)
success = False
for line in unified_diff(fblog_before, fblog_after):
if line.startswith('+') and pattern.search(line):
success = True
assert success

View File

@ -2,15 +2,16 @@
#
# id: bugs.core_2712
# title: Do not print "invalid request BLR" for par.cpp errors with valid BLR
# decription:
#
# decription:
#
# tracker_id: CORE-2712
# min_versions: ['3.0.0']
# versions: 3.0
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
from firebird.driver import DatabaseError
# version: 3.0
# resources: None
@ -23,26 +24,26 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
#
# import os
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# db_conn.close()
# msg=''
#
#
# att1 = kdb.connect(dsn=dsn)
# cur1 = att1.cursor()
# cur1.execute("recreate table test(x int)")
# att1.commit()
# cur1.execute("insert into test values(1)")
# att1.commit()
#
#
# att2 = kdb.connect(dsn=dsn)
# cur2 = att2.cursor()
# cur2.execute("select 1 from rdb$database")
#
#
# cur1.execute("drop table test")
# try:
# cur2.prep("update test set x=-x")
@ -50,22 +51,27 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# except Exception as e:
# msg = e[0]
# print(msg)
#
#
# att1.close()
# att2.close()
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
expected_stdout_1 = """
Error while preparing SQL statement:
- SQLCODE: -219
- table id 128 is not defined
"""
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, capsys):
with act_1.db.connect() as att1:
cur1 = att1.cursor()
cur1.execute("recreate table test(x int)")
att1.commit()
cur1.execute("insert into test values(1)")
att1.commit()
with act_1.db.connect() as att2:
cur2 = att2.cursor()
cur2.execute("select 1 from rdb$database")
cur1.execute("drop table test")
with pytest.raises(DatabaseError, match='.*table id [0-9]+ is not defined.*'):
cur2.prepare("update test set x=-x")
att2.commit()

View File

@ -2,21 +2,21 @@
#
# id: bugs.core_2724
# title: Validate or transform string of DML queries so that engine internals doesn't receive malformed strings
# decription:
# decription:
# Code from doc/sql.extensions/README.ddl_triggers.txt was taken as basis for this test
# (see ticket issue: "This situation happened with DDL triggers ...").
# Several DB objects are created here and their DDL contain unicode (Greek) text.
# Attachment these issues these DDL intentionally is run with charset = NONE.
# Attachment these issues these DDL intentionally is run with charset = NONE.
# This charset (NONE) should result in question marks after we finish DDL and want to query log table
# that was filled by DDL trigger and contains issued DDL statements.
#
#
# tracker_id: CORE-2724
# min_versions: ['3.0']
# versions: 3.0
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 3.0
# resources: None
@ -41,7 +41,7 @@ init_script_1 = """
result_info blob sub_type text
);
commit;
set term ^;
create trigger trig_ddl_log_before before any ddl statement
as
@ -52,18 +52,18 @@ init_script_1 = """
-- didn't run, the log will survive.
in autonomous transaction do
begin
select coalesce(c.rdb$character_set_name, '??? NULL ???')
from mon$attachments a
left join rdb$character_sets c on a.mon$character_set_id = c.rdb$character_set_id
where a.mon$attachment_id = current_connection
into v_current_connection_cset;
insert into ddl_log (id, moment, current_connection_cset,
insert into ddl_log (id, moment, current_connection_cset,
event_type, object_type, ddl_event, object_name,
old_object_name, new_object_name, sql_text, ok, result_info)
values (next value for ddl_seq,
'now',
values (next value for ddl_seq,
'now',
:v_current_connection_cset,
rdb$get_context('DDL_TRIGGER', 'EVENT_TYPE'),
rdb$get_context('DDL_TRIGGER', 'OBJECT_TYPE'),
@ -79,7 +79,7 @@ init_script_1 = """
end
end
^
-- Note: the above trigger will fire for this DDL command. It's good idea to use -nodbtriggers
-- when working with them!
create trigger trig_ddl_log_after after any ddl statement
@ -89,14 +89,14 @@ init_script_1 = """
-- record inserted on the BEFORE trigger autonomous transaction if user transaction is not
-- READ COMMITTED.
in autonomous transaction do
update ddl_log set ok = 'Y',
update ddl_log set ok = 'Y',
result_info = 'Τα πάντα ήταν επιτυχής' -- Everything has completed successfully
where id = rdb$get_context('USER_SESSION', 'trig_ddl_log_id');
end
^
set term ;^
commit;
-- So lets delete the record about trig_ddl_log_after creation.
delete from ddl_log;
commit;
@ -106,33 +106,33 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
#
# import os
# import time
# import subprocess
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# db_conn.close()
#
#
# #---------------------------------------------
#
#
# def flush_and_close(file_handle):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb'):
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
@ -140,13 +140,13 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# os.remove( f_names_list[i] )
# if os.path.isfile( f_names_list[i]):
# print('ERROR: can not remove file ' + f_names_list[i])
#
#
# #--------------------------------------------
#
#
#
#
# sql_check=''' delete from ddl_log;
# commit;
#
#
# create domain dm_name varchar(50) check (value in ('αμορτισέρ', 'κόμβο', 'σωλήνα', 'φέροντα', 'βραχίονα'));
# recreate table t1 (
# saller_id integer -- αναγνωριστικό εμπόρου // ID of saler
@ -155,39 +155,39 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# );
# commit;
# set list on;
#
#
# select id, current_connection_cset, sql_text, result_info, ddl_event, object_name
# from ddl_log order by id;
#
#
# commit;
# drop table t1;
# drop domain dm_name;
# exit;
# '''
#
#
# f_check_sql = open( os.path.join(context['temp_directory'],'tmp_check_2724.sql'), 'w')
# f_check_sql.write(sql_check)
# flush_and_close( f_check_sql )
#
#
# ##########################################################################################
#
#
# f_ch_none_log = open( os.path.join(context['temp_directory'],'tmp_ch_none_2724.log'), 'w')
# f_ch_none_err = open( os.path.join(context['temp_directory'],'tmp_ch_none_2724.err'), 'w')
#
#
# subprocess.call( [context['isql_path'], dsn, "-i", f_check_sql.name,
# "-ch", "none"],
# stdout = f_ch_none_log,
# stderr = f_ch_none_err
# )
#
#
# flush_and_close( f_ch_none_log )
# flush_and_close( f_ch_none_err )
#
#
# ##########################################################################################
#
#
# f_ch_utf8_log = open( os.path.join(context['temp_directory'],'tmp_ch_utf8_2724.log'), 'w')
# f_ch_utf8_err = open( os.path.join(context['temp_directory'],'tmp_ch_utf8_2724.err'), 'w')
#
#
# subprocess.call( [context['isql_path'], dsn, "-user", user_name, "-password", user_password, "-i", f_check_sql.name,
# "-ch", "utf8"],
# stdout = f_ch_utf8_log,
@ -195,50 +195,53 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
# )
# flush_and_close( f_ch_utf8_log )
# flush_and_close( f_ch_utf8_err )
#
#
#
#
# f_list = [f_ch_none_log, f_ch_none_err, f_ch_utf8_log, f_ch_utf8_err]
# for f in f_list:
# with open( f.name,'r') as f:
# print(f.read())
#
#
#
#
# # Cleanup
# #########
# time.sleep(1)
#
#
# f_list.append(f_check_sql)
# cleanup( [i.name for i in f_list] )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
expected_stdout_1 = """
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1_a = """
ID 2
CURRENT_CONNECTION_CSET NONE
SQL_TEXT
CURRENT_CONNECTION_CSET NONE
SQL_TEXT
create domain dm_name varchar(50) check (value in ('??????????????????', '??????????', '????????????', '??????????????', '????????????????'))
RESULT_INFO
RESULT_INFO
Τα πάντα ήταν επιτυχής
DDL_EVENT CREATE DOMAIN
OBJECT_NAME DM_NAME
ID 3
CURRENT_CONNECTION_CSET NONE
SQL_TEXT
CURRENT_CONNECTION_CSET NONE
SQL_TEXT
recreate table t1 (
saller_id integer -- ?????????????????????????? ?????????????? // ID of saler
,customer_id integer -- ?????????????????????????? ???????????? // ID of customer
,product_name dm_name
)
RESULT_INFO
RESULT_INFO
Τα πάντα ήταν επιτυχής
DDL_EVENT CREATE TABLE
OBJECT_NAME T1
OBJECT_NAME T1
"""
expected_stdout_1_b = """
ID 6
CURRENT_CONNECTION_CSET UTF8
CURRENT_CONNECTION_CSET UTF8
SQL_TEXT 80:0
create domain dm_name varchar(50) check (value in ('αμορτισέρ', 'κόμβο', 'σωλήνα', 'φέροντα', 'βραχίονα'))
RESULT_INFO 80:2
@ -247,22 +250,48 @@ expected_stdout_1 = """
OBJECT_NAME DM_NAME
ID 7
CURRENT_CONNECTION_CSET UTF8
SQL_TEXT
CURRENT_CONNECTION_CSET UTF8
SQL_TEXT
recreate table t1 (
saller_id integer -- αναγνωριστικό εμπόρου // ID of saler
,customer_id integer -- αναγνωριστικό πελάτη // ID of customer
,product_name dm_name
)
RESULT_INFO
RESULT_INFO
Τα πάντα ήταν επιτυχής
DDL_EVENT CREATE TABLE
OBJECT_NAME T1
OBJECT_NAME T1
"""
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
sql_check = '''
delete from ddl_log;
commit;
create domain dm_name varchar(50) check (value in ('αμορτισέρ', 'κόμβο', 'σωλήνα', 'φέροντα', 'βραχίονα'));
recreate table t1 (
saller_id integer -- αναγνωριστικό εμπόρου // ID of saler
,customer_id integer -- αναγνωριστικό πελάτη // ID of customer
,product_name dm_name
);
commit;
set list on;
select id, current_connection_cset, sql_text, result_info, ddl_event, object_name
from ddl_log order by id;
commit;
drop table t1;
drop domain dm_name;
exit;
'''
#
act_1.expected_stdout = expected_stdout_1_a
act_1.isql(switches=[], charset='NONE', input=sql_check)
assert act_1.clean_stdout == act_1.clean_expected_stdout
#
act_1.reset()
act_1.expected_stdout = expected_stdout_1_b
act_1.isql(switches=[], charset='UTF8', input=sql_check)
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,15 +2,15 @@
#
# id: bugs.core_2788
# title: isql extracts the array dimensions after the character set name
# decription:
#
# decription:
#
# tracker_id: CORE-2788
# min_versions: ['3.0']
# versions: 3.0
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 3.0
# resources: None
@ -27,29 +27,29 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# import time
# import subprocess
# from subprocess import Popen
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# db_conn.close()
#
#
# #---------------------------------------------
#
#
# def flush_and_close(file_handle):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb'):
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
@ -57,20 +57,20 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# os.remove( f_names_list[i] )
# if os.path.isfile( f_names_list[i]):
# print('ERROR: can not remove file ' + f_names_list[i])
#
#
# #--------------------------------------------
#
#
# sql_ddl=''' create domain dm_test as char(1) character set iso8859_1[1:2];
# create domain dm_test as char(1)[1:2] character set iso8859_1;
# commit;
# show domain dm_test;
# '''
#
#
#
#
# f_init_sql = open( os.path.join(context['temp_directory'],'tmp_init_2788.sql'), 'w')
# f_init_sql.write(sql_ddl)
# flush_and_close( f_init_sql )
#
#
# f_init_log = open( os.path.join(context['temp_directory'],'tmp_init_2788.log'), 'w')
# f_init_err = open( os.path.join(context['temp_directory'],'tmp_init_2788.err'), 'w')
# subprocess.call( [context['isql_path'], dsn, "-i", f_init_sql.name],
@ -79,35 +79,35 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# )
# # This file should be empty:
# flush_and_close( f_init_log )
#
#
# # This file should contain error messages about 1st 'CREATE DOMAIN' statement that has syntax trouble:
# flush_and_close( f_init_err )
#
#
# # This file should contain error messages about 1st 'CREATE DOMAIN' statement that has syntax trouble:
# with open( f_init_err.name,'r') as f:
# print(f.read())
#
#
#
#
# f_xmeta_log = open( os.path.join(context['temp_directory'],'tmp_xmeta_2788.log'), 'w')
# f_xmeta_err = open( os.path.join(context['temp_directory'],'tmp_xmeta_2788.err'), 'w')
# subprocess.call( [context['isql_path'], dsn, "-x"], stdout = f_xmeta_log, stderr = f_xmeta_err)
#
#
# # This file should contain metadata - domain definition:
# flush_and_close( f_xmeta_log )
#
#
# # This file should be empty:
# flush_and_close( f_xmeta_err )
#
#
# att1 = fdb.connect(dsn=dsn.encode())
# cur1=att1.cursor()
# cur1.execute("drop domain dm_test")
# att1.commit()
#
#
# att1.close()
#
#
# # This shoudl issue "There is no domain DM_TEST in this database":
# runProgram('isql',[dsn, '-q'],'show domain dm_test;')
#
#
# f_apply_log = open( os.path.join(context['temp_directory'],'tmp_apply_2788.log'), 'w')
# f_apply_err = open( os.path.join(context['temp_directory'],'tmp_apply_2788.err'), 'w')
# subprocess.call( [context['isql_path'], dsn, "-i", f_xmeta_log.name],
@ -117,49 +117,82 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# # Both of these files should be empty:
# flush_and_close( f_apply_log )
# flush_and_close( f_apply_err )
#
#
# # This shoudl issue DDL of just created domain:
# runProgram('isql',[dsn, '-q'],'show domain dm_test;')
#
#
# # No output should be here:
# with open( f_xmeta_err.name,'r') as f:
# print(f.read())
#
#
# # No output should be here:
# with open( f_apply_log.name,'r') as f:
# print(f.read())
#
#
#
#
# # No output should be here:
# with open( f_apply_err.name,'r') as f:
# print(f.read())
#
#
#
#
# ################################################
# # Cleanup
# time.sleep(1)
# cleanup( [i.name for i in (f_init_sql,f_init_log,f_init_err,f_xmeta_log,f_xmeta_err,f_apply_log,f_apply_err) ] )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
Statement failed, SQLSTATE = 42000
Dynamic SQL Error
-SQL error code = -104
-Token unknown - line 1, column 57
-[
DM_TEST ARRAY OF [2]
CHAR(1) CHARACTER SET ISO8859_1 Nullable
"""
expected_stderr_1 = """
There is no domain DM_TEST in this database
"""
DM_TEST ARRAY OF [2]
CHAR(1) CHARACTER SET ISO8859_1 Nullable
"""
expected_stderr_1_a = """
Statement failed, SQLSTATE = 42000
Dynamic SQL Error
-SQL error code = -104
-Token unknown - line 1, column 57
-[
"""
expected_stderr_1_b = """
There is no domain DM_TEST in this database
"""
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
sql_ddl = ''' create domain dm_test as char(1) character set iso8859_1[1:2];
create domain dm_test as char(1)[1:2] character set iso8859_1;
commit;
show domain dm_test;
'''
act_1.expected_stderr = expected_stderr_1_a
act_1.expected_stdout = expected_stdout_1
act_1.isql(switches=[], input=sql_ddl)
assert act_1.clean_stderr == act_1.clean_expected_stderr
assert act_1.clean_stdout == act_1.clean_expected_stdout
#
act_1.reset()
act_1.isql(switches=['-x'])
xmeta = act_1.stdout
#
with act_1.db.connect() as con:
c = con.cursor()
c.execute('drop domain dm_test')
con.commit()
#
act_1.reset()
act_1.expected_stderr = expected_stderr_1_b
act_1.isql(switches=['-q'], input='show domain dm_test;')
assert act_1.clean_stderr == act_1.clean_expected_stderr
#
act_1.reset()
act_1.isql(switches=[], input=xmeta)
#
act_1.reset()
act_1.expected_stdout = expected_stdout_1
act_1.isql(switches=['-q'], input='show domain dm_test;')
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,15 +2,15 @@
#
# id: bugs.core_2817
# title: If stored procedure or trigger contains query with PLAN ORDER it could fail after disconnect of attachment where procedure rigger executed first time
# decription:
#
# decription:
#
# tracker_id: CORE-2817
# min_versions: ['2.5.0']
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 2.5
# resources: None
@ -39,9 +39,9 @@ init_script_1 = """
set term ^;
create or alter procedure sp_test(a_odd smallint) as
declare c_ord cursor for (
select s
from test
where mod(x, 2) = :a_odd
select s
from test
where mod(x, 2) = :a_odd
order by x
);
declare v_s type of column test.s;
@ -57,7 +57,7 @@ init_script_1 = """
end
^ -- sp_test
set term ;^
commit;
commit;
"""
db_1 = db_factory(sql_dialect=3, init=init_script_1)
@ -65,32 +65,36 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# test_script_1
#---
# import fdb
#
#
# db_conn.close()
# att1 = kdb.connect(dsn=dsn.encode(),user='SYSDBA',password='masterkey')
# att2 = kdb.connect(dsn=dsn.encode(),user='SYSDBA',password='masterkey')
#
#
# cur1 = att1.cursor()
# cur2 = att2.cursor()
#
#
# sp_run='execute procedure sp_test'
#
#
# cur1.execute('execute procedure sp_test(0)')
# cur2.execute('execute procedure sp_test(1)')
#
#
# att1.commit()
# att1.close()
#
#
# cur2.execute('execute procedure sp_test(1)')
# att2.close()
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
with act_1.db.connect() as att2:
with act_1.db.connect() as att1:
cur1 = att1.cursor()
cur2 = att2.cursor()
cur1.execute('execute procedure sp_test(0)')
cur2.execute('execute procedure sp_test(1)')
att1.commit()
cur2.execute('execute procedure sp_test(1)')

View File

@ -2,14 +2,14 @@
#
# id: bugs.core_2831
# title: isql shouldn't display db and user name when extracting a script
# decription:
# decription:
# tracker_id: CORE-2831
# min_versions: ['2.0.6', '2.1.4', '2.5']
# versions: 3.0
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 3.0
# resources: None
@ -25,12 +25,12 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
# #
# runProgram('isql',['-x',dsn,'-user',user_name,'-pass',user_password])
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
act_1.isql(switches=['-x'])
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,32 +2,30 @@
#
# id: bugs.core_2861
# title: Cannot remove user with dot in login
# decription:
# Since 10.01.2016 this test (for 3.0) is based on totally new algorithm with checking ability of
# normal work with randomly generated logins. These logins consists only of punctuation chars and
# decription:
# Since 10.01.2016 this test (for 3.0) is based on totally new algorithm with checking ability of
# normal work with randomly generated logins. These logins consists only of punctuation chars and
# for sure will have at least one dot.
# The reason of this replacement was failed results on Classic 3.0 when 'gsec' utility is invoked.
# Code for 2.5 was not changed and is preserved (though it was missed for 2.5 before, but it works OK).
#
#
# See http://web.firebirdsql.org/download/prerelease/results/archive/ for builds: 3.0.0.32266 3.0.0.32268
#
#
# Correctness of current code was verified by batch scenario, totally about ~1500 iterations was done.
# Several samples of logins that were be checked:
# ,(/;.>_:%$^`.&<|#?=[~\\*}-{@)
# >=[{+%\\.&|~$`(;#._,])}?*@:^!
# }^\\*@.)#>|/;&!=~`]<[,?.-:(%.
#
#
# NOTE: currently we EXCLUDE single and double quotes from random login because of CORE-5072.
#
#
# This login is handled then by both FBSVCMGR and ISQL utilities:
# 1) run FBSVCMGR and:
# 1.1) add user
# 1.1) add user
# 1.2) modifying some of its attributes (password, firstname etc).
# NOTE! We do *not* run 'fbsvcmgr action_delete_user' because it does not work (at least on build 32268)
# ######################################################################################################
# COMMAND: fbsvcmgr localhost/3333:service_mgr user sysdba password masterkey action_delete_user dbname C:\\MIX
# irebird
# b30\\security3.fdb sec_username john
# COMMAND: fbsvcmgr localhost/3333:service_mgr user sysdba password masterkey action_delete_user dbname C:\\MIX\\firebird\\fb30\\security3.fdb sec_username john
# STDERR: unexpected item in service parameter block, expected isc_spb_sec_username
# (sent letter to Alex, 09-jan-2016 22:34; after getting reply about this issue test can be further changed).
# 2) run ISQL and:
@ -35,23 +33,27 @@
# 2.2) create this login again;
# 2.3) modifying some of this login attributes;
# 2.4) drop it finally.
#
#
# See also:
# CORE-1810 ("Usernames with '.' character"; login 'JOHN.SMITH' is used there).
# CORE-3000 (use of unquoted reserved word ADMIN as user name in SQL command).
#
#
# tracker_id: CORE-2861
# min_versions: ['2.5.0']
# versions: 3.0
# qmid:
# qmid:
import pytest
from firebird.qa import db_factory, isql_act, Action
import string
from random import sample, choice
from firebird.qa import db_factory, python_act, Action
from firebird.driver.types import UserInfo
# version: 3.0
# resources: None
substitutions_1 = [('[ ]+', ' '), ('[\t]*', ' '), ('.* Name: .*', ' Name: <name.with.puncts>')]
substitutions_1 = [('.* name: .*', 'Name: <name.with.puncts>'),
('.*USER_NAME.*', 'USER_NAME <name.with.puncts>')]
init_script_1 = """"""
@ -66,60 +68,60 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# import string
# from random import sample, choice
# from fdb import services
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# db_name=db_conn.database_name
# db_conn.close()
#
#
# svc = services.connect(host='localhost')
# security_db_name = svc.get_security_database_path() # path+name of security DB
# svc.close()
#
#
# # Useful links related to this .fbt:
# # https://docs.python.org/2/library/string.html
# # http://stackoverflow.com/questions/3854692/generate-password-in-python
# # http://stackoverflow.com/questions/2257441/random-string-generation-with-upper-case-letters-and-digits-in-python
# # http://stackoverflow.com/questions/1024049/is-it-pythonic-to-import-inside-functions
# # http://stackoverflow.com/questions/3095071/in-python-what-happens-when-you-import-inside-of-a-function
#
#
# #--------------------------------------------
#
#
# def flush_and_close(file_handle):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb'):
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
# if os.path.isfile( f_names_list[i]):
# os.remove( f_names_list[i] )
#
#
#
#
# #--------------------------------------------
#
#
# def svc_show_user( f_svc_log, f_svc_err, title_msg, security_db_name, sec_user ):
#
#
# global subprocess
#
#
# f_svc_log.seek(0,2)
# f_svc_log.write("\\n")
# f_svc_log.write(title_msg)
# f_svc_log.write("\\n")
# f_svc_log.seek(0,2)
#
#
# subprocess.call( [ context['fbsvcmgr_path'],
# "localhost:service_mgr",
# "action_display_user_adm",
@ -129,38 +131,38 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout=f_svc_log, stderr=f_svc_err
# )
# return
#
#
# #--------------------------------------------
#
#
# f_svc_log=open( os.path.join(context['temp_directory'],'tmp_2861_fbsvc.log'), 'w')
# f_svc_err=open( os.path.join(context['temp_directory'],'tmp_2861_fbsvc.err'), 'w')
#
# chars = string.punctuation
#
# # + string.digits
#
# chars = string.punctuation
#
# # + string.digits
# #string.letters + string.digits
# # do NOT: chars = string.printable -- it includes whitespaces, i.e. LF etc!
#
#
# # NB: maximal part of user name that is displayed in fbsvcmgr action_display_user is only 28 chars.
# # We build user name as two parts delimited by dot, so max. length of these parts is bound to 13,
# # otherwise total length of user name will be 14+1+14 = 29 and we'll get mismatch on expected stdout.
#
#
#
#
# '''
# length = 13
# dotted_user=''.join(sample(chars,length)).replace('"','.').replace("'",'.')
# dotted_user=dotted_user+'.'+''.join(sample(chars,length))
# dotted_user=dotted_user.replace('"','""').replace("'","''")
# '''
#
#
# length = 28
# dotted_user=''.join(sample(chars,length)).replace('"','.').replace("'",'.')
# quoted_user='"'+dotted_user+'"'
#
#
# f_svc_log.write("Try to add user with name: "+quoted_user)
# f_svc_log.write("\\n")
# f_svc_log.seek(0,2)
#
#
# subprocess.call( [ context['fbsvcmgr_path'],
# "localhost:service_mgr",
# "action_add_user",
@ -171,15 +173,15 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# ],
# stdout=f_svc_log, stderr=f_svc_err
# )
#
#
# svc_show_user( f_svc_log, f_svc_err, "Try to display user after adding.", security_db_name, quoted_user )
#
#
# f_svc_log.seek(0,2)
# f_svc_log.write("\\n")
# f_svc_log.write("Try to modify user: change password and some attributes.")
# f_svc_log.write("\\n")
# f_svc_log.seek(0,2)
#
#
# subprocess.call( [ context['fbsvcmgr_path'],
# "localhost:service_mgr",
# "action_modify_user",
@ -193,23 +195,23 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# ],
# stdout=f_svc_log, stderr=f_svc_err
# )
#
#
# svc_show_user( f_svc_log, f_svc_err, "Try to display user after modifying.", security_db_name, quoted_user )
#
#
# f_svc_log.seek(0,2)
# f_svc_log.write("\\n")
# f_svc_log.write("All done.")
# f_svc_log.write("\\n")
#
#
# flush_and_close( f_svc_log )
# flush_and_close( f_svc_err )
#
#
# #####################################
#
#
# # Now we drop user (using ISQL - fbsvcmgr currently does not work)
# # and then create + modify + drop him again by ISQL.
#
#
#
#
# isql_txt='''---- %s
# set list on;
# --set echo on;
@ -217,24 +219,24 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# from sec$users
# where upper(sec$user_name)=upper('%s');
# commit;
#
#
# -- select * from v_sec; commit; -- ==> FOO.RIO.BAR, in UPPER case (left after fbsvcmgr add_user)
#
#
# drop user %s;
# commit;
#
#
# select 'Try to add user with name: ' || '%s' as isql_msg from rdb$database;
#
#
# create or alter user %s password '123' grant admin role;
# commit;
#
#
# select 'Try to display user after adding.' as isql_msg from rdb$database;
#
#
# select * from v_sec;
# commit;
#
#
# select 'Try to modify user: change password and some attributes.' as isql_msg from rdb$database;
#
#
# alter user %s
# password 'Zeppelin'
# firstname 'John'
@ -243,97 +245,147 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# revoke admin role
# ;
# commit;
#
#
# select 'Try to display user after modifying.' as isql_msg from rdb$database;
# select * from v_sec;
# commit;
#
#
# select 'Try to drop user.' as isql_msg from rdb$database;
# drop user %s;
# commit;
# select 'All done.' as isql_msg from rdb$database;
# ''' % (dotted_user, dotted_user, quoted_user.upper(), dotted_user, quoted_user, quoted_user, quoted_user )
#
#
# f_sql_txt=open( os.path.join(context['temp_directory'],'tmp_2861_isql.sql'), 'w')
# f_sql_txt.write(isql_txt)
# flush_and_close( f_sql_txt )
#
#
# f_sql_log=open( os.path.join(context['temp_directory'],'tmp_2861_isql.log'), 'w')
# f_sql_err=open( os.path.join(context['temp_directory'],'tmp_2861_isql.err'), 'w')
#
#
# subprocess.call( [ context['isql_path'], dsn, "-i", f_sql_txt.name ],
# stdout=f_sql_log, stderr=f_sql_err
# )
#
#
# flush_and_close( f_sql_log )
# flush_and_close( f_sql_err )
#
#
# with open( f_svc_log.name,'r') as f:
# l = [l for l in f.readlines() if l.strip()]
#
#
# for line in l:
# print("SVC STDOUT: "+line.replace(dotted_user.upper(),"<name.with.puncts>") )
#
#
# with open( f_svc_err.name,'r') as f:
# l = [l for l in f.readlines() if l.strip()]
#
#
# for line in l:
# print("SVC STDERR: "+line+", user: "+dotted_user)
#
#
# with open( f_sql_log.name,'r') as f:
# l = [l for l in f.readlines() if l.strip()]
#
#
# for line in l:
# print("SQL STDOUT: "+line.replace(dotted_user,"<name.with.puncts>"))
#
#
# with open( f_sql_err.name,'r') as f:
# l = [l for l in f.readlines() if l.strip()]
#
#
# for line in l:
# print("SQL STDERR: "+line+", user: "+dotted_user)
#
#
#
#
# # Cleanup.
# ##########
#
#
# time.sleep(1)
# cleanup( [i.name for i in (f_svc_log,f_svc_err,f_sql_log,f_sql_err,f_sql_txt)] )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
SVC STDOUT: Try to add user with name: "<name.with.puncts>"
SVC STDOUT: Try to display user after adding.
SVC STDOUT: Login Full name uid gid adm
SVC STDOUT: <name.with.puncts> 0 0 yes
SVC STDOUT: Try to modify user: change password and some attributes.
SVC STDOUT: Try to display user after modifying.
SVC STDOUT: Login Full name uid gid adm
SVC STDOUT: <name.with.puncts> Ozzy The Terrible Osbourne 0 0 no
SVC STDOUT: All done.
SQL STDOUT: ISQL_MSG Try to add user with name: <name.with.puncts>
SQL STDOUT: ISQL_MSG Try to display user after adding.
SQL STDOUT: SEC$USER_NAME <name.with.puncts>
SQL STDOUT: SEC$FIRST_NAME <null>
SQL STDOUT: SEC$MIDDLE_NAME <null>
SQL STDOUT: SEC$LAST_NAME <null>
SQL STDOUT: SEC$ADMIN <true>
SQL STDOUT: ISQL_MSG Try to modify user: change password and some attributes.
SQL STDOUT: ISQL_MSG Try to display user after modifying.
SQL STDOUT: SEC$USER_NAME <name.with.puncts>
SQL STDOUT: SEC$FIRST_NAME John
SQL STDOUT: SEC$MIDDLE_NAME Bonzo The Beast
SQL STDOUT: SEC$LAST_NAME Bonham
SQL STDOUT: SEC$ADMIN <false>
SQL STDOUT: ISQL_MSG Try to drop user.
SQL STDOUT: ISQL_MSG All done.
"""
ISQL_MSG Try to add user with name: <name.with.puncts>
ISQL_MSG Try to display user after adding.
SEC$USER_NAME <name.with.puncts>
SEC$FIRST_NAME <null>
SEC$MIDDLE_NAME <null>
SEC$LAST_NAME <null>
SEC$ADMIN <true>
ISQL_MSG Try to modify user: change password and some attributes.
ISQL_MSG Try to display user after modifying.
SEC$USER_NAME <name.with.puncts>
SEC$FIRST_NAME John
SEC$MIDDLE_NAME Bonzo The Beast
SEC$LAST_NAME Bonham
SEC$ADMIN <false>
ISQL_MSG Try to drop user.
ISQL_MSG All done.
"""
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
chars = string.punctuation
length = 28
dotted_user = ''.join(sample(chars, length)).replace('"', '.').replace("'", '.')
quoted_user = '"' + dotted_user + '"'
# Via services
with act_1.connect_server() as srv:
srv.user.add(user_name=quoted_user, password='foobarkey', admin=True)
user = srv.user.get(user_name=quoted_user)
assert user == UserInfo(user_name=dotted_user, password=None, admin=True,
first_name='', middle_name='', last_name='', user_id=0,
group_id=0)
srv.user.update(user_name=quoted_user, password='BSabbath', first_name='Ozzy',
middle_name='The Terrible', last_name='Osbourne', admin=False)
user = srv.user.get(user_name=quoted_user)
assert user == UserInfo(user_name=dotted_user, password=None, admin=False,
first_name='Ozzy', middle_name='The Terrible', last_name='Osbourne',
user_id=0, group_id=0)
srv.user.delete(user_name=quoted_user)
assert srv.user.get(user_name=quoted_user) is None
# Via ISQL
isql_txt = f'''---- {dotted_user}
set list on;
--set echo on;
create or alter view v_sec as select sec$user_name, sec$first_name, sec$middle_name, sec$last_name, sec$admin
from sec$users
where upper(sec$user_name)=upper('{dotted_user}');
commit;
select 'Try to add user with name: ' || '{dotted_user}' as isql_msg from rdb$database;
create or alter user {quoted_user} password '123' grant admin role;
commit;
select 'Try to display user after adding.' as isql_msg from rdb$database;
select * from v_sec;
commit;
select 'Try to modify user: change password and some attributes.' as isql_msg from rdb$database;
alter user {quoted_user}
password 'Zeppelin'
firstname 'John'
middlename 'Bonzo The Beast'
lastname 'Bonham'
revoke admin role
;
commit;
select 'Try to display user after modifying.' as isql_msg from rdb$database;
select * from v_sec;
commit;
select 'Try to drop user.' as isql_msg from rdb$database;
drop user {quoted_user};
commit;
select 'All done.' as isql_msg from rdb$database;
'''
act_1.expected_stdout = expected_stdout_1
act_1.isql(switches=[], input=isql_txt)
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,29 +2,33 @@
#
# id: bugs.core_2879
# title: Sweep could raise error : page 0 is of wrong type (expected 6, found 1)
# decription:
# decription:
# Test receives content of firebird.log _before_ and _after_ running query that is show in the ticket.
# Then we compare these two files.
# Difference between them should relate ONLY to sweep start and finish details, and NOT about page wrong type.
#
#
# Checked on: WI-V2.5.7.27024, WI-V3.0.1.32570, WI-T4.0.0.316 -- all works OK.
# Refactored 01.02.2020, checked on:
# 4.0.0.1759 SS: 4.754s.
# 3.0.6.33240 SS: 3.704s.
# 2.5.9.27119 SS: 6.607s.
#
#
# tracker_id: CORE-2879
# min_versions: ['2.5.1']
# versions: 2.5.1
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
import time
import subprocess
from pathlib import Path
from difflib import unified_diff
from firebird.qa import db_factory, python_act, Action, temp_file
# version: 2.5.1
# resources: None
substitutions_1 = [('\t+', ' '), ('^((?!start|finish|expected|page|wrong).)*$', '')]
substitutions_1 = [('^((?!start|finish|expected|page|wrong).)*$', '')] # ('\t+', ' '),
init_script_1 = """"""
@ -32,7 +36,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
#
# import os
# import sys
# import subprocess
@ -41,61 +45,61 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# import time
# import datetime
# from datetime import datetime
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# engine = str(db_conn.engine_version)
# db_file = db_conn.database_name # "$(DATABASE_LOCATION)bugs.core_2879.fdb"
#
#
# db_conn.close()
#
#
# #--------------------------------------------
#
#
# def flush_and_close(file_handle):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb'):
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
# if os.path.isfile( f_names_list[i]):
# os.remove( f_names_list[i] )
#
#
# #--------------------------------------------
#
#
# def svc_get_fb_log( engine, f_fb_log ):
#
#
# global subprocess
#
#
# if engine.startswith('2.5'):
# get_firebird_log_key='action_get_ib_log'
# else:
# get_firebird_log_key='action_get_fb_log'
#
#
# subprocess.call([ context['fbsvcmgr_path'],
# "localhost:service_mgr",
# get_firebird_log_key
# ],
# stdout=f_fb_log,
# stdout=f_fb_log,
# stderr=subprocess.STDOUT
# )
#
#
# return
#
#
# #-----------------------------------------------------
#
#
# sql_ddl=''' set list on;
# set term ^;
# execute block returns (dts timestamp, sql varchar(80)) as
@ -110,110 +114,155 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# sql = 'create global temporary table ' || :s || ' (id int);';
# execute statement sql with autonomous transaction;
# suspend;
#
#
# dts = 'now';
# sql = 'drop table ' || :s || ';';
# execute statement sql with autonomous transaction;
# suspend;
#
#
# i = i + 1;
# end
# end ^
# set term ;^
# '''
#
#
# f_isql_cmd=open( os.path.join(context['temp_directory'],'tmp_make_lot_GTT_2879.sql'), 'w', buffering = 0)
# f_isql_cmd.write(sql_ddl)
# f_isql_cmd.close()
#
#
# # Get content of firebird.log BEFORE test:
# ##########################################
#
#
# f_fblog_before=open( os.path.join(context['temp_directory'],'tmp_2879_fblog_before.txt'), 'w', buffering = 0)
# svc_get_fb_log( engine, f_fblog_before )
# flush_and_close( f_fblog_before )
#
#
# # LAUNCH ISQL ASYNCHRONOUSLY
# ############################
#
#
# f_isql_log=open( os.path.join(context['temp_directory'],'tmp_make_lot_GTT_2879.log'), 'w', buffering = 0)
# p_isql=subprocess.Popen( [context['isql_path'], dsn, "-i", f_isql_cmd.name],
# stdout=f_isql_log,
# stdout=f_isql_log,
# stderr=subprocess.STDOUT
# )
# #------------
# time.sleep(2)
# #------------
#
#
# # LAUNCH SWEEP while ISQL is working:
# # ############
# fbsvc_log=open( os.path.join(context['temp_directory'],'tmp_svc_2879.log'), 'w', buffering = 0)
# subprocess.call( [ context['fbsvcmgr_path'],"localhost:service_mgr", "action_repair", "dbname", db_file, "rpr_sweep_db"], stdout=fbsvc_log, stderr=subprocess.STDOUT )
# flush_and_close( fbsvc_log )
#
#
# p_isql.terminate()
# f_isql_log.close()
#
#
#
#
# # Get content of firebird.log AFTER test:
# #########################################
#
#
# f_fblog_after=open( os.path.join(context['temp_directory'],'tmp_2879_fblog_after.txt'), 'w', buffering = 0)
# svc_get_fb_log( engine, f_fblog_after )
# flush_and_close( f_fblog_after )
#
#
# # 07.08.2016
# # DIFFERENCE in the content of firebird.log should be EMPTY:
# ####################
#
#
# oldfb=open(f_fblog_before.name, 'r')
# newfb=open(f_fblog_after.name, 'r')
#
#
# difftext = ''.join(difflib.unified_diff(
# oldfb.readlines(),
# oldfb.readlines(),
# newfb.readlines()
# ))
# oldfb.close()
# newfb.close()
#
#
# f_diff_txt=open( os.path.join(context['temp_directory'],'tmp_2879_diff.txt'), 'w', buffering = 0)
# f_diff_txt.write(difftext)
# flush_and_close( f_diff_txt )
#
# # NB: difflib.unified_diff() can show line(s) that present in both files, without marking that line(s) with "+".
#
# # NB: difflib.unified_diff() can show line(s) that present in both files, without marking that line(s) with "+".
# # Usually these are 1-2 lines that placed just BEFORE difference starts.
# # So we have to check output before display diff content: lines that are really differ must start with "+".
#
#
# with open( f_diff_txt.name,'r') as f:
# for line in f:
# if line.startswith('+') and line.split('+'):
# print(line.replace('+',' '))
#
#
# # 01.02.2020. We have to change DB state to full shutdown and bring it back online
# # in order to prevent "Object in use" while fbtest will try to drop this DB
# #####################################
# runProgram('gfix',[dsn,'-shut','full','-force','0'])
# runProgram('gfix',[dsn,'-online'])
#
#
#
#
#
#
# # Cleanup:
# ##########
# time.sleep(1)
# cleanup( [i.name for i in (f_isql_cmd, f_isql_log, fbsvc_log, f_fblog_before,f_fblog_after, f_diff_txt)] )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
Sweep is started by SYSDBA
Sweep is finished
"""
"""
isql_script = temp_file('test-script.sql')
@pytest.mark.version('>=2.5.1')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, isql_script: Path, capsys):
isql_script.write_text(''' set list on;
set term ^;
execute block returns (dts timestamp, sql varchar(80)) as
declare i int;
declare s varchar(256);
begin
i = 1;
while (i < 32767) do
begin
s = 'tmp' || :i;
dts = 'now';
sql = 'create global temporary table ' || :s || ' (id int);';
execute statement sql with autonomous transaction;
suspend;
dts = 'now';
sql = 'drop table ' || :s || ';';
execute statement sql with autonomous transaction;
suspend;
i = i + 1;
end
end ^
set term ;^
''')
with act_1.connect_server() as srv:
# Get content of firebird.log BEFORE test
srv.info.get_log()
log_before = srv.readlines()
p_isql = subprocess.Popen([act_1.vars['isql'], act_1.db.dsn, '-i', str(isql_script)],
stderr=subprocess.STDOUT)
time.sleep(2)
# LAUNCH SWEEP while ISQL is working
srv.database.sweep(database=str(act_1.db.db_path))
p_isql.terminate()
# Get content of firebird.log AFTER test
srv.info.get_log()
log_after = srv.readlines()
for line in unified_diff(log_before, log_after):
if line.startswith('+') and line.split('+'):
print(line.replace('+', ' '))
act_1.expected_stdout = expected_stdout_1
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,25 +2,28 @@
#
# id: bugs.core_2912
# title: Exception when upper casing string with lowercase y trema (code 0xFF in ISO8859_1 )
# decription:
# decription:
# 02-mar-2021. Re-implemented in order to have ability to run this test on Linux.
# Ttest creates table and fills it with non-ascii characters in init_script, using charset = UTF8.
# Test creates table and fills it with non-ascii characters in init_script, using charset = UTF8.
# Then it generates .sql script for running it in separae ISQL process.
# This script makes connection to test DB using charset = ISO8859_1 and perform several queries.
# Result will be redirected to .log and .err files (they will be encoded, of course, also in ISO8859_1).
# Finally, we open .log file (using codecs package), convert its content to UTF8 and show in expected_stdout.
#
#
# Checked on:
# * Windows: 4.0.0.2377, 3.0.8.33420, 2.5.9.27152
# * Windows: 4.0.0.2377, 3.0.8.33420, 2.5.9.27152
# * Linux: 4.0.0.2377, 3.0.8.33415
#
#
# [pcisar] 16.11.2021
# This test fails as UPPER('ÿ') does not work properly
#
# tracker_id: CORE-2912
# min_versions: ['2.5.3']
# versions: 2.5.3
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 2.5.3
# resources: None
@ -33,39 +36,39 @@ init_script_1 = """
insert into test(c) values('ÿ');
insert into test(c) values('Faÿ');
commit;
create index test_cu on test computed by (upper (c collate iso8859_1));
commit;
create index test_cu on test computed by (upper (c collate iso8859_1));
commit;
"""
db_1 = db_factory(charset='ISO8859_1', sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
#
# import os
# import codecs
# import subprocess
# import time
#
#
# db_conn.close()
#
#
# #--------------------------------------------
#
#
# def flush_and_close( file_handle ):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
@ -76,13 +79,13 @@ db_1 = db_factory(charset='ISO8859_1', sql_dialect=3, init=init_script_1)
# else:
# print('Unrecognized type of element:', f_names_list[i], ' - can not be treated as file.')
# del_name = None
#
#
# if del_name and os.path.isfile( del_name ):
# os.remove( del_name )
#
#
# #--------------------------------------------
#
# sql_txt=''' set names ISO8859_1;
#
# sql_txt=''' set names ISO8859_1;
# connect '%(dsn)s' user '%(user_name)s' password '%(user_password)s';
# set list on;
# select upper('aÿb') au from rdb$database;
@ -95,15 +98,15 @@ db_1 = db_factory(charset='ISO8859_1', sql_dialect=3, init=init_script_1)
# -- will be specified not in UPPER case (see note in CORE-4740 08/Apr/15 05:48 PM):
# select c, upper(c) cu from test where c similar to '[[:ALPHA:]]{1,}ÿ%%';
# set plan on;
# select c from test where upper (c collate iso8859_1) = upper('ÿ');
# select c, upper(c) cu from test where upper (c collate iso8859_1) starting with upper('Faÿ');
# select c from test where upper (c collate iso8859_1) = upper('ÿ');
# select c, upper(c) cu from test where upper (c collate iso8859_1) starting with upper('Faÿ');
# ''' % dict(globals(), **locals())
#
#
# f_run_sql = open( os.path.join(context['temp_directory'], 'tmp_2912_iso8859_1.sql'), 'w' )
# f_run_sql.write( sql_txt.decode('utf8').encode('iso-8859-1') )
# flush_and_close( f_run_sql )
# # result: file tmp_2912_iso8859_1.sql is encoded in iso8859_1 (aka 'latin-1')
#
#
# f_run_log = open( os.path.splitext(f_run_sql.name)[0]+'.log', 'w')
# f_run_err = open( os.path.splitext(f_run_sql.name)[0]+'.err', 'w')
# subprocess.call( [ context['isql_path'], '-q', '-i', f_run_sql.name ],
@ -112,52 +115,67 @@ db_1 = db_factory(charset='ISO8859_1', sql_dialect=3, init=init_script_1)
# )
# flush_and_close( f_run_log )
# flush_and_close( f_run_err )
#
#
# # result: output will be encoded in iso9959_1, error log must be empty.
# with codecs.open(f_run_log.name, 'r', encoding='iso-8859-1' ) as f:
# stdout_encoded_in_latin_1 = f.readlines()
#
#
# with codecs.open(f_run_err.name, 'r', encoding='iso-8859-1' ) as f:
# stderr_encoded_in_latin_1 = f.readlines()
#
#
# for i in stdout_encoded_in_latin_1:
# print( i.encode('utf8') )
#
#
# # NO error must occur:
# ######################
# for i in stderr_encoded_in_latin_1:
# print( 'UNEXPECTED STDERR: ', i.encode('utf8') )
#
#
# # cleanup:
# ###########
# ###########
# cleanup( (f_run_sql, f_run_log, f_run_err) )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
AU AÿB
C ÿ
CU ÿ
C Faÿ
CU FAÿ
C Faÿ
CU FAÿ
C Faÿ
CU FAÿ
C Faÿ
CU FAÿ
PLAN (TEST INDEX (TEST_CU))
C ÿ
PLAN (TEST INDEX (TEST_CU))
C Faÿ
CU FAÿ
"""
AU AÿB
C ÿ
CU ÿ
C Faÿ
CU FAÿ
C Faÿ
CU FAÿ
C Faÿ
CU FAÿ
C Faÿ
CU FAÿ
PLAN (TEST INDEX (TEST_CU))
C ÿ
PLAN (TEST INDEX (TEST_CU))
C Faÿ
CU FAÿ
"""
@pytest.mark.version('>=2.5.3')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
sql_txt = '''set names ISO8859_1;
set list on;
select upper('aÿb') au from rdb$database;
select c, upper(c) cu from test where c starting with upper('ÿ');
select c, upper(c) cu from test where c containing 'Faÿ';
select c, upper(c) cu from test where c starting with 'Faÿ';
select c, upper(c) cu from test where c like 'Faÿ%';
-- ### ACHTUNG ###
-- As of WI-V2.5.4.26857, following will FAILS if character class "alpha"
-- will be specified not in UPPER case (see note in CORE-4740 08/Apr/15 05:48 PM):
select c, upper(c) cu from test where c similar to '[[:ALPHA:]]{1,}ÿ%';
set plan on;
select c from test where upper (c collate iso8859_1) = upper('ÿ');
select c, upper(c) cu from test where upper (c collate iso8859_1) starting with upper('Faÿ');
'''
act_1.expected_stdout = expected_stdout_1
act_1.isql(switches=['-q'], charset='ISO8859_1', input=sql_txt)
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,45 +2,46 @@
#
# id: bugs.core_2940
# title: Trace output could contain garbage data left from filtered out statements
# decription:
# decription:
# 1. Obtain engine_version from built-in context variable.
# 2. Make config for trace in proper format according to FB engine version, with 'exclude_filter' parameter from ticket.
# 3. Launch trace session in separate child process using 'FBSVCMGR action_trace_start'
# 4. Run ISQL with test commands. Only one of these command does not contain token that is specified in 'exclude_filter'
# 5. Stop trace session. Output its log with filtering only statistics info.
#
#
# Checked on: WI-V2.5.5.26916 (SS, SC, CS); WI-V3.0.0.32008 (SS, SC, CS). Result: OK.
# Checked on: 3.0.1.32525, 4.0.0.238 // 07-jun-2016
# ::: NB :::
# Several delays (time.sleep) added in main thread because of OS buffering. Couldn't switch this buffering off.
#
#
#
#
# ::: NB ::: 07-jun-2016.
#
#
# WI-T4.0.0.238 will issue in trace log following statement with its statistics ("1 records fetched"):
# ===
# with recursive role_tree as (
# select rdb$relation_name as nm, 0 as ur from rdb$user_privileges
# where
# rdb$privilege = 'M' and rdb$field_name = 'D'
# and rdb$user = ? and rdb$user_type = 8
# union all
# select rdb$role_name as nm, 1 as ur from rdb$roles
# with recursive role_tree as (
# select rdb$relation_name as nm, 0 as ur from rdb$user_privileges
# where
# rdb$privilege = 'M' and rdb$field_name = 'D'
# and rdb$user = ? and rdb$user_type = 8
# union all
# select rdb$role_name as nm, 1 as ur from rdb$roles
# where rdb$role_name =...
#
#
# param0 = varchar(93), "SYSDBA"
# param1 = varchar(93), "NONE"
# ===
# We have to SKIP this statement statistics and start to check only "our" selects from rdb$database
# see usage of first_sttm_pattern and trace_stat_pattern.
#
#
# tracker_id: CORE-2940
# min_versions: ['2.5.0']
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from threading import Thread
from firebird.qa import db_factory, python_act, Action
# version: 2.5
# resources: None
@ -58,40 +59,40 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# from subprocess import Popen
# import time
# import re
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# engine=str(db_conn.engine_version)
# db_conn.close()
#
#
#
#
# #--------------------------------------------
#
#
# def flush_and_close(file_handle):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb'):
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
# if os.path.isfile( f_names_list[i]):
# os.remove( f_names_list[i] )
#
#
# #--------------------------------------------
#
#
#
#
# txt25 = '''# Trace config, format for 2.5. Generated auto, do not edit!
# <database %[\\\\\\\\/]bugs.core_2940.fdb>
# enabled true
@ -102,15 +103,15 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# log_statement_finish true
# print_plan true
# print_perf true
# time_threshold 0
# time_threshold 0
# </database>
# '''
#
#
# # NOTES ABOUT TRACE CONFIG FOR 3.0:
# # 1) Header contains `database` clause in different format vs FB 2.5: its data must be enclosed with '{' '}'
# # 2) Name and value must be separated by EQUALITY sign ('=') in FB-3 trace.conf, otherwise we get runtime error:
# # element "<. . .>" have no attribute value set
#
#
# txt30 = '''# Trace config, format for 3.0. Generated auto, do not edit!
# database=%[\\\\\\\\/]bugs.core_2940.fdb
# {
@ -122,7 +123,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# log_statement_finish = true
# print_plan = true
# print_perf = true
# time_threshold = 0
# time_threshold = 0
# }
# '''
# trccfg=open( os.path.join(context['temp_directory'],'tmp_trace_2940.cfg'), 'w')
@ -131,40 +132,40 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# else:
# trccfg.write(txt30)
# trccfg.close()
#
#
# trclog=open( os.path.join(context['temp_directory'],'tmp_trace_2940.log'), 'w')
# trclog.close()
# trclst=open( os.path.join(context['temp_directory'],'tmp_trace_2940.lst'), 'w')
# trclst.close()
#
#
# #####################################################
# # Starting trace session in new child process (async.):
#
#
# f_trclog=open(trclog.name,'w')
# # Execute a child program in a new process, redirecting STDERR to the same target as of STDOUT:
# p_trace=Popen([context['fbsvcmgr_path'], "localhost:service_mgr",
# "action_trace_start",
# "trc_cfg", trccfg.name],
# stdout=f_trclog, stderr=subprocess.STDOUT)
#
#
# # Wait! Trace session is initialized not instantly!
# time.sleep(1)
#
#
# #####################################################
# # Running ISQL with test commands:
#
#
# sqltxt='''
# set list on;
# -- statistics for this statement SHOULD appear in trace log:
# select 1 k1 from rdb$database;
# select 1 k1 from rdb$database;
# commit;
#
#
# -- statistics for this statement should NOT appear in trace log:
# select 2 k2 from rdb$types rows 2 /* no_trace*/;
#
# select 2 k2 from rdb$types rows 2 /* no_trace*/;
#
# -- statistics for this statement should NOT appear in trace log:
# select 3 no_trace from rdb$types rows 3;
#
# select 3 no_trace from rdb$types rows 3;
#
# -- statistics for this statement should NOT appear in trace log:
# set term ^;
# execute block returns(k4 int) as
@ -174,15 +175,15 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# ^
# set term ;^
# '''
#
#
# runProgram('isql',[dsn,'-n'],sqltxt)
#
#
# # do NOT remove this otherwise trace log can contain only message about its start before being closed!
# time.sleep(3)
#
#
# #####################################################
# # Getting ID of launched trace session and STOP it:
#
#
# # Save active trace session info into file for further parsing it and obtain session_id back (for stop):
# f_trclst=open(trclst.name,'w')
# subprocess.call([context['fbsvcmgr_path'], "localhost:service_mgr",
@ -190,7 +191,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout=f_trclst, stderr=subprocess.STDOUT
# )
# flush_and_close( f_trclst )
#
#
# trcssn=0
# with open( trclst.name,'r') as f:
# for line in f:
@ -201,7 +202,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# trcssn=word
# i=i+1
# break
#
#
# # Result: `trcssn` is ID of active trace session. Now we have to terminate it:
# f_trclst=open(trclst.name,'a')
# f_trclst.seek(0,2)
@ -211,14 +212,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout=f_trclst, stderr=subprocess.STDOUT
# )
# flush_and_close( f_trclst )
#
#
# # Terminate child process of launched trace session (though it should already be killed):
# p_trace.terminate()
# flush_and_close( f_trclog )
#
#
# #####################################################
# # Output log of trace session, with filtering only info about statistics ('fetches'):
#
#
# first_sttm_pattern=re.compile("select 1 k1")
# trace_stat_pattern=re.compile("1 records fetched")
# flag=0
@ -228,24 +229,74 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# flag=1
# if flag==1 and trace_stat_pattern.match(line):
# print(line)
#
#
# # Cleanup:
# ##########
# time.sleep(1)
#
#
# cleanup([i.name for i in (trccfg,trclst,trclog)])
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
1 records fetched
"""
"""
test_script_1 = """
set list on;
-- statistics for this statement SHOULD appear in trace log:
select 1 k1 from rdb$database;
commit;
-- statistics for this statement should NOT appear in trace log:
select 2 k2 from rdb$types rows 2 /* no_trace*/;
-- statistics for this statement should NOT appear in trace log:
select 3 no_trace from rdb$types rows 3;
-- statistics for this statement should NOT appear in trace log:
set term ^;
execute block returns(k4 int) as
begin
for select 4 from rdb$types rows 4 into k4 do suspend;
end -- no_trace
^
set term ;^
"""
def trace_session(act: Action):
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
f'database=%[\\\\/]{act.db.db_path.name}',
'{',
' enabled = true',
' #include_filter',
' exclude_filter = %no_trace%',
' log_connections = true',
' log_transactions = true',
' log_statement_finish = true',
' print_plan = true',
' print_perf = true',
' time_threshold = 0',
'}']
with act.connect_server() as srv:
srv.trace.start(config='\n'.join(cfg30))
for line in srv:
print(line)
@pytest.mark.version('>=3.0')
def test_1(act_1: Action, capsys):
trace_thread = Thread(target=trace_session, args=[act_1])
trace_thread.start()
act_1.isql(switches=['-n'], input=test_script_1)
with act_1.connect_server() as srv:
for session in list(srv.trace.sessions.keys()):
srv.trace.stop(session_id=session)
trace_thread.join(1.0)
if trace_thread.is_alive():
pytest.fail('Trace thread still alive')
act_1.expected_stdout = expected_stdout_1
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")

View File

@ -2,21 +2,23 @@
#
# id: bugs.core_2981
# title: Error in Trace plugin (use local symbols in query)
# decription:
# decription:
# Test prepares trace config as it was mentioned in the ticket, then creates .sql with russian text in UTF8 encoding
# and run trace and ISQL.
# Finally, we compare content of firebird.log before and after running this query (it should be empty) and check that
# size of error log of trace session is zero.
#
#
# Checked on: WI-V2.5.7.27024, WI-V3.0.1.32570, WI-T4.0.0.316 -- all works OK.
#
#
# tracker_id: CORE-2981
# min_versions: ['2.5.1']
# versions: 2.5.1
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from threading import Thread
from difflib import unified_diff
from firebird.qa import db_factory, python_act, Action
# version: 2.5.1
# resources: None
@ -34,60 +36,60 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# import subprocess
# import difflib
# from subprocess import Popen
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# engine = str(db_conn.engine_version)
# db_conn.close()
#
#
# #--------------------------------------------
#
#
# def flush_and_close(file_handle):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb'):
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
# if os.path.isfile( f_names_list[i]):
# os.remove( f_names_list[i] )
#
#
# #--------------------------------------------
#
#
# def svc_get_fb_log( engine, f_fb_log ):
#
#
# global subprocess
#
#
# if engine.startswith('2.5'):
# get_firebird_log_key='action_get_ib_log'
# else:
# get_firebird_log_key='action_get_fb_log'
#
#
# subprocess.call([ context['fbsvcmgr_path'],
# "localhost:service_mgr",
# get_firebird_log_key
# ],
# stdout=f_fb_log,
# stdout=f_fb_log,
# stderr=subprocess.STDOUT
# )
#
#
# return
#
#
# #--------------------------------------------
#
#
#
#
# txt25 = '''# Trace config, format for 2.5. Generated auto, do not edit!
# <database %[\\\\\\\\/]bugs.core_2981.fdb>
# enabled true
@ -115,20 +117,20 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# max_blr_length 500
# max_dyn_length 500
# max_arg_length 80
# max_arg_count 30
# max_arg_count 30
# </database>
# <services>
# enabled false
# log_services false
# log_service_query false
# </services>
# </services>
# '''
#
#
# # NOTES ABOUT TRACE CONFIG FOR 3.0:
# # 1) Header contains `database` clause in different format vs FB 2.5: its data must be enclosed with '{' '}'
# # 2) Name and value must be separated by EQUALITY sign ('=') in FB-3 trace.conf, otherwise we get runtime error:
# # element "<. . .>" have no attribute value set
#
#
# txt30 = '''# Trace config, format for 3.0. Generated auto, do not edit!
# database=%[\\\\\\\\/]bugs.core_2981.fdb
# {
@ -156,7 +158,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# max_blr_length = 500
# max_dyn_length = 500
# max_arg_length = 80
# max_arg_count = 30
# max_arg_count = 30
# }
# services {
# enabled = false
@ -164,52 +166,52 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# log_service_query = false
# }
# '''
#
#
# f_trccfg=open( os.path.join(context['temp_directory'],'tmp_trace_2981.cfg'), 'w')
# if engine.startswith('2.5'):
# f_trccfg.write(txt25)
# else:
# f_trccfg.write(txt30)
# flush_and_close( f_trccfg )
#
#
# # Get content of firebird.log BEFORE test:
# ##########################################
#
#
# f_fblog_before=open( os.path.join(context['temp_directory'],'tmp_2981_fblog_before.txt'), 'w')
# svc_get_fb_log( engine, f_fblog_before )
# flush_and_close( f_fblog_before )
#
#
# # Starting trace session in new child process (async.):
# #######################################################
#
#
# f_trclog=open( os.path.join(context['temp_directory'],'tmp_trace_2981.log'), 'w')
# f_trcerr=open( os.path.join(context['temp_directory'],'tmp_trace_2981.err'), 'w')
#
#
# # Execute a child program in a new process, redirecting STDERR to the same target as of STDOUT:
# p_trace=Popen([context['fbsvcmgr_path'], "localhost:service_mgr",
# "action_trace_start",
# "trc_cfg", f_trccfg.name],
# stdout=f_trclog,
# stdout=f_trclog,
# stderr=f_trcerr
# )
#
#
# # Wait! Trace session is initialized not instantly!
# time.sleep(2)
#
#
# localized_query='''
# set list on;
# select '*Лев Николаевич Толстой *
#
#
# *Анна Каренина *
#
#
# /Мне отмщение, и аз воздам/
#
#
# *ЧАСТЬ ПЕРВАЯ*
#
#
# *I *
#
#
# Все счастливые семьи похожи друг на друга, каждая несчастливая
# семья несчастлива по-своему.
# семья несчастлива по-своему.
# Все смешалось в доме Облонских. Жена узнала, что муж был в связи
# с бывшею в их доме француженкою-гувернанткой, и объявила мужу, что
# не может жить с ним в одном доме. Положение это продолжалось уже
@ -221,20 +223,20 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# своих комнат, мужа третий день не было дома. Дети бегали по всему
# дому, как потерянные; англичанка поссорилась с экономкой и написала
# записку приятельнице, прося приискать ей новое место; повар ушел еще
# вчера со двора, во время обеда; черная кухарка и кучер просили расчета.
# вчера со двора, во время обеда; черная кухарка и кучер просили расчета.
# На третий день после ссоры князь Степан Аркадьич Облонский --
# Стива, как его звали в свете, -- в обычный час, то есть в восемь
# часов утра, проснулся не в спальне жены, а в своем кабинете, на
# сафьянном диване... Он повернул свое полное, выхоленное тело на
# пружинах дивана, как бы желая опять заснуть надолго, с другой
# стороны крепко обнял подушку и прижался к ней щекой; но вдруг
# вскочил, сел на диван и открыл глаза.
# вскочил, сел на диван и открыл глаза.
# "Да, да, как это было? -- думал он, вспоминая сон. -- Да, как это
# было? Да! Алабин давал обед в Дармштадте; нет, не в Дармштадте, а
# что-то американское. Да, но там Дармштадт был в Америке. Да, Алабин
# давал обед на стеклянных столах, да, -- и столы пели: Il mio tesoro,
# и не Il mio tesoro, а что-то лучше, и какие-то маленькие графинчики,
# и они же женщины", -- вспоминал он.
# и они же женщины", -- вспоминал он.
# Глаза Степана Аркадьича весело заблестели, и он задумался,
# улыбаясь. "Да, хорошо было, очень хорошо. Много еще там было
# отличного, да не скажешь словами и мыслями даже наяву не выразишь".
@ -244,27 +246,27 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# по старой, девятилетней привычке, не вставая, потянулся рукой к тому
# месту, где в спальне у него висел халат. И тут он вспомнил вдруг,
# как и почему он спит не в спальне жены, а в кабинете; улыбка исчезла
# с его лица, он сморщил лоб.
# с его лица, он сморщил лоб.
# "Ах, ах, ах! Ааа!.." -- замычал он, вспоминая все, что было. И
# его воображению представились опять все подробности ссоры с женою,
# вся безвыходность его положения и мучительнее всего собственная вина
# его.
# его.
# "Да! она не простит и не может простить. И всего ужаснее то, что
# виной всему я, виной я, а не виноват. В этом-то вся драма, -- думал
# он. -- Ах, ах, ах!" -- приговаривал он с отчаянием, вспоминая самые
# тяжелые для себя впечатления из этой ссоры.
# тяжелые для себя впечатления из этой ссоры.
# Неприятнее всего была та первая минута, когда он, вернувшись из
# театра, веселый и довольный, с огромною грушей для жены в руке, не
# нашел жены в гостиной; к удивлению, не нашел ее и в кабинете и,
# наконец, увидал ее в спальне с несчастною, открывшею все, запиской в
# руке.
# руке.
# Она, эта вечно озабоченная, и хлопотливая, и недалекая, какою он
# считал ее, Долли, неподвижно сидела с запиской в руке и с выражением
# ужаса, отчаяния и гнева смотрела на него.
# -- Что это? это? -- спрашивала она, указывая на записку.
# ужаса, отчаяния и гнева смотрела на него.
# -- Что это? это? -- спрашивала она, указывая на записку.
# И при этом воспоминании, как это часто бывает, мучала Степана
# Аркадьича не столько самое событие, сколько то, как он ответил на
# эти слова жены.
# эти слова жены.
# С ним случилось в эту минуту то, что случается с людьми, когда
# они неожиданно уличены в чем-нибудь слишком постыдном. Он не сумел
# приготовить свое лицо к тому положению, в которое он становился
@ -273,45 +275,45 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# равнодушным -- все было бы лучше того, что он сделал! -- его лицо
# совершенно невольно ("рефлексы головного мозга", -- подумал Степан
# Аркадьич, который любил физиологию), совершенно невольно вдруг
# улыбнулось привычною, доброю и потому глупою улыбкой.
# улыбнулось привычною, доброю и потому глупою улыбкой.
# Эту глупую улыбку он не мог простить себе. Увидав эту улыбку,
# Долли вздрогнула, как от физической боли, разразилась, со
# свойственною ей горячностью, потоком жестоких слов и выбежала из
# комнаты. С тех пор она не хотела видеть мужа.
# "Всему виной эта глупая улыбка", -- думал Степан Аркадьич.
# комнаты. С тех пор она не хотела видеть мужа.
# "Всему виной эта глупая улыбка", -- думал Степан Аркадьич.
# "Но что же делать? что делать?" -- с отчаянием говорил он себе и
# не находил ответа.
# не находил ответа.
# ' from rdb$database;
# '''
# f_utf8 = open( os.path.join(context['temp_directory'],'tmp_2981_run.sql'), 'w')
# f_utf8.write(localized_query)
# flush_and_close( f_utf8 )
#
#
# # RUN QUERY WITH NON-ASCII CHARACTERS
# #####################################
#
#
# f_run_log = open( os.path.join(context['temp_directory'],'tmp_2981_run.log'), 'w')
# f_run_err = open( os.path.join(context['temp_directory'],'tmp_2981_run.err'), 'w')
# subprocess.call( [context['isql_path'], dsn, "-q", "-i", f_utf8.name, '-ch', 'utf8' ],
# stdout = f_run_log,
# stderr = f_run_err
# )
#
#
# flush_and_close( f_run_log )
# flush_and_close( f_run_err )
#
#
# #####################################################
# # Getting ID of launched trace session and STOP it:
#
#
# # Save active trace session info into file for further parsing it and obtain session_id back (for stop):
# f_trclst=open( os.path.join(context['temp_directory'],'tmp_trace_2981.lst'), 'w')
# subprocess.call([context['fbsvcmgr_path'], "localhost:service_mgr",
# "action_trace_list"],
# stdout=f_trclst,
# stdout=f_trclst,
# stderr=subprocess.STDOUT
# )
# flush_and_close( f_trclst )
#
#
# trcssn=0
# with open( f_trclst.name,'r') as f:
# for line in f:
@ -322,7 +324,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# trcssn=word
# i=i+1
# break
#
#
# # Result: `trcssn` is ID of active trace session. Now we have to terminate it:
# f_trclst=open(f_trclst.name,'a')
# f_trclst.seek(0,2)
@ -332,23 +334,23 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout=f_trclst, stderr=subprocess.STDOUT
# )
# flush_and_close( f_trclst )
#
#
# # do NOT remove this delay: trase session can not be stopped immediatelly:
# time.sleep(2)
#
#
# # Terminate child process of launched trace session (though it should already be killed):
# p_trace.terminate()
# flush_and_close( f_trclog )
# flush_and_close( f_trcerr )
#
#
#
#
# # Get content of firebird.log AFTER test:
# #########################################
#
#
# f_fblog_after=open( os.path.join(context['temp_directory'],'tmp_2981_fblog_after.txt'), 'w')
# svc_get_fb_log( engine, f_fblog_after )
# flush_and_close( f_fblog_after )
#
#
# # STDERR for ISQL (that created DB) and trace session - they both must be EMPTY:
# #################
# f_list=[f_run_err, f_trcerr]
@ -358,43 +360,184 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# with open( f_name,'r') as f:
# for line in f:
# print("Unexpected STDERR, file "+f_name+": "+line)
#
#
# # DIFFERENCE in the content of firebird.log should be EMPTY:
# ####################
#
#
# oldfb=open(f_fblog_before.name, 'r')
# newfb=open(f_fblog_after.name, 'r')
#
#
# difftext = ''.join(difflib.unified_diff(
# oldfb.readlines(),
# oldfb.readlines(),
# newfb.readlines()
# ))
# oldfb.close()
# newfb.close()
#
#
# f_diff_txt=open( os.path.join(context['temp_directory'],'tmp_2981_diff.txt'), 'w')
# f_diff_txt.write(difftext)
# flush_and_close( f_diff_txt )
#
#
# with open( f_diff_txt.name,'r') as f:
# for line in f:
# print("Unexpected DIFF in firebird.log: "+line)
#
#
#
#
#
#
# # Cleanup:
# ###########
# time.sleep(1)
# cleanup( [i.name for i in (f_run_log, f_run_err, f_trccfg, f_trclst, f_trcerr, f_fblog_before,f_fblog_after, f_diff_txt, f_trclog, f_utf8)] )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
test_script_1 = """
set list on;
select '*Лев Николаевич Толстой *
*Анна Каренина *
/Мне отмщение, и аз воздам/
*ЧАСТЬ ПЕРВАЯ*
*I *
Все счастливые семьи похожи друг на друга, каждая несчастливая
семья несчастлива по-своему.
Все смешалось в доме Облонских. Жена узнала, что муж был в связи
с бывшею в их доме француженкою-гувернанткой, и объявила мужу, что
не может жить с ним в одном доме. Положение это продолжалось уже
третий день и мучительно чувствовалось и самими супругами, и всеми
членами семьи, и домочадцами. Все члены семьи и домочадцы
чувствовали, что нет смысла в их сожительстве и что на каждом
постоялом дворе случайно сошедшиеся люди более связаны между собой,
чем они, члены семьи и домочадцы Облонских. Жена не выходила из
своих комнат, мужа третий день не было дома. Дети бегали по всему
дому, как потерянные; англичанка поссорилась с экономкой и написала
записку приятельнице, прося приискать ей новое место; повар ушел еще
вчера со двора, во время обеда; черная кухарка и кучер просили расчета.
На третий день после ссоры князь Степан Аркадьич Облонский --
Стива, как его звали в свете, -- в обычный час, то есть в восемь
часов утра, проснулся не в спальне жены, а в своем кабинете, на
сафьянном диване... Он повернул свое полное, выхоленное тело на
пружинах дивана, как бы желая опять заснуть надолго, с другой
стороны крепко обнял подушку и прижался к ней щекой; но вдруг
вскочил, сел на диван и открыл глаза.
"Да, да, как это было? -- думал он, вспоминая сон. -- Да, как это
было? Да! Алабин давал обед в Дармштадте; нет, не в Дармштадте, а
что-то американское. Да, но там Дармштадт был в Америке. Да, Алабин
давал обед на стеклянных столах, да, -- и столы пели: Il mio tesoro,
и не Il mio tesoro, а что-то лучше, и какие-то маленькие графинчики,
и они же женщины", -- вспоминал он.
Глаза Степана Аркадьича весело заблестели, и он задумался,
улыбаясь. "Да, хорошо было, очень хорошо. Много еще там было
отличного, да не скажешь словами и мыслями даже наяву не выразишь".
И, заметив полосу света, пробившуюся сбоку одной из суконных стор,
он весело скинул ноги с дивана, отыскал ими шитые женой (подарок ко
дню рождения в прошлом году), обделанные в золотистый сафьян туфли и
по старой, девятилетней привычке, не вставая, потянулся рукой к тому
месту, где в спальне у него висел халат. И тут он вспомнил вдруг,
как и почему он спит не в спальне жены, а в кабинете; улыбка исчезла
с его лица, он сморщил лоб.
"Ах, ах, ах! Ааа!.." -- замычал он, вспоминая все, что было. И
его воображению представились опять все подробности ссоры с женою,
вся безвыходность его положения и мучительнее всего собственная вина
его.
"Да! она не простит и не может простить. И всего ужаснее то, что
виной всему я, виной я, а не виноват. В этом-то вся драма, -- думал
он. -- Ах, ах, ах!" -- приговаривал он с отчаянием, вспоминая самые
тяжелые для себя впечатления из этой ссоры.
Неприятнее всего была та первая минута, когда он, вернувшись из
театра, веселый и довольный, с огромною грушей для жены в руке, не
нашел жены в гостиной; к удивлению, не нашел ее и в кабинете и,
наконец, увидал ее в спальне с несчастною, открывшею все, запиской в
руке.
Она, эта вечно озабоченная, и хлопотливая, и недалекая, какою он
считал ее, Долли, неподвижно сидела с запиской в руке и с выражением
ужаса, отчаяния и гнева смотрела на него.
-- Что это? это? -- спрашивала она, указывая на записку.
И при этом воспоминании, как это часто бывает, мучала Степана
Аркадьича не столько самое событие, сколько то, как он ответил на
эти слова жены.
С ним случилось в эту минуту то, что случается с людьми, когда
они неожиданно уличены в чем-нибудь слишком постыдном. Он не сумел
приготовить свое лицо к тому положению, в которое он становился
перед женой после открытия его вины. Вместо того чтоб оскорбиться,
отрекаться, оправдываться, просить прощения, оставаться даже
равнодушным -- все было бы лучше того, что он сделал! -- его лицо
совершенно невольно ("рефлексы головного мозга", -- подумал Степан
Аркадьич, который любил физиологию), совершенно невольно вдруг
улыбнулось привычною, доброю и потому глупою улыбкой.
Эту глупую улыбку он не мог простить себе. Увидав эту улыбку,
Долли вздрогнула, как от физической боли, разразилась, со
свойственною ей горячностью, потоком жестоких слов и выбежала из
комнаты. С тех пор она не хотела видеть мужа.
"Всему виной эта глупая улыбка", -- думал Степан Аркадьич.
"Но что же делать? что делать?" -- с отчаянием говорил он себе и
не находил ответа.
' from rdb$database;
"""
def trace_session(act: Action):
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
f'database=%[\\\\/]{act.db.db_path.name}',
'{',
' enabled = true',
' include_filter = %(SELECT|INSERT|UPDATE|DELETE)%',
' exclude_filter = %no_trace%',
' log_connections = true',
' log_transactions = true',
' log_statement_prepare = true',
' log_statement_free = true',
' log_statement_start = true',
' log_statement_finish = true',
' log_trigger_start = true',
' log_trigger_finish = true',
' log_context = true',
' print_plan = true',
' print_perf = true',
' time_threshold = 0',
' max_sql_length = 5000',
' max_blr_length = 500',
' max_dyn_length = 500',
' max_arg_length = 80',
' max_arg_count = 30',
'}',
'services {',
' enabled = false',
' log_services = false',
' log_service_query = false',
'}']
with act.connect_server() as srv:
srv.encoding = 'utf8'
srv.trace.start(config='\n'.join(cfg30))
for line in srv:
pass # we are not interested in trace output
@pytest.mark.version('>=2.5.1')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
# Get content of firebird.log BEFORE test
with act_1.connect_server() as srv:
srv.info.get_log()
log_before = srv.readlines()
trace_thread = Thread(target=trace_session, args=[act_1])
trace_thread.start()
# RUN QUERY WITH NON-ASCII CHARACTERS
act_1.isql(switches=['-n', '-q'], input=test_script_1)
with act_1.connect_server() as srv:
for session in list(srv.trace.sessions.keys()):
srv.trace.stop(session_id=session)
trace_thread.join(1.0)
if trace_thread.is_alive():
pytest.fail('Trace thread still alive')
# Get content of firebird.log AFTER test
with act_1.connect_server() as srv:
srv.info.get_log()
log_after = srv.readlines()
assert '\n'.join(unified_diff(log_before, log_after)) == ''

View File

@ -2,7 +2,7 @@
#
# id: bugs.core_2988
# title: Concurrent transaction number not reported if lock timeout occurs
# decription:
# decription:
# 08-aug-2018.
# ::: ACHTUNG :::
# Important change has been added in FB 4.0.
@ -16,29 +16,32 @@
# as ticket says in its case-1:
# ===
# set transaction read committed no record_version lock timeout 10;
# select * from test;
# select * from test;
# ===
# For this reason it was decided to create separate section for major version 4.0
# and use UPDATE statement instead of 'select * from test' (UPDATE also must READ
# and use UPDATE statement instead of 'select * from test' (UPDATE also must READ
# data before changing).
#
#
# Checked on:
# FB25SC, build 2.5.9.27115: OK, 3.750s.
# FB30SS, build 3.0.4.33022: OK, 4.343s.
# FB40SS, build 4.0.0.1154: OK, 4.875s.
#
#
# tracker_id: CORE-2988
# min_versions: ['2.5.4']
# versions: 3.0, 4.0
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, isql_act, Action, python_act
from firebird.driver import TPB, TraAccessMode, Isolation
# version: 3.0
# resources: None
substitutions_1 = [('record not found for user:.*', ''), ('-concurrent transaction number is.*', '-concurrent transaction number is'), ('-At block line: [\\d]+, col: [\\d]+', '-At block line')]
substitutions_1 = [('record not found for user:.*', ''),
('-concurrent transaction number is.*', '-concurrent transaction number is'),
('-At block line: [\\d]+, col: [\\d]+', '-At block line')]
init_script_1 = """"""
@ -49,7 +52,7 @@ test_script_1 = """
commit;
create user tmp$2988 password 'tmp$2988';
commit;
recreate table test (id integer);
insert into test values(1);
commit;
@ -60,7 +63,7 @@ test_script_1 = """
set transaction lock timeout 1;
update test set id = id;
set term ^;
execute block as
declare v_usr char(31) = 'tmp$2988';
@ -76,10 +79,10 @@ test_script_1 = """
^
set term ;^
rollback;
set transaction read committed no record_version lock timeout 1;
update test set id = id;
set term ^;
execute block as
declare v_usr char(31) = 'tmp$2988';
@ -95,11 +98,11 @@ test_script_1 = """
^
set term ;^
rollback;
set list on;
set transaction read committed no record_version lock timeout 1;
select id from test with lock;
set term ^;
execute block as
declare v_usr char(31) = 'tmp$2988';
@ -114,7 +117,7 @@ test_script_1 = """
begin
end
end
execute statement ('select id from test with lock')
with autonomous transaction
as user v_usr password v_pwd
@ -155,7 +158,8 @@ act_1 = isql_act('db_1', test_script_1, substitutions=substitutions_1)
expected_stdout_1 = """
ID 1
"""
"""
expected_stderr_1 = """
Statement failed, SQLSTATE = HY000
record not found for user: TMP$2988
@ -177,7 +181,7 @@ expected_stderr_1 = """
-read conflicts with concurrent update
-concurrent transaction number is 24
-At block line: 7, col: 9
"""
"""
@pytest.mark.version('>=3.0,<4.0')
def test_1(act_1: Action):
@ -190,7 +194,8 @@ def test_1(act_1: Action):
# version: 4.0
# resources: None
substitutions_2 = [('^((?!concurrent transaction number is).)*$', ''), ('[\\-]{0,1}concurrent transaction number is [0-9]+', 'concurrent transaction number is')]
substitutions_2 = [('^((?!concurrent transaction number is).)*$', ''),
('[\\-]{0,1}concurrent transaction number is [0-9]+', 'concurrent transaction number is')]
init_script_2 = """
create table test(id int, x int, constraint test_pk primary key(id) using index test_pk);
@ -203,42 +208,42 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
# test_script_2
#---
#
#
# import os
# db_conn.close()
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# con = fdb.connect(dsn = dsn)
#
# tx1 = con.trans()
#
# tx1 = con.trans()
# tx1.begin()
# cur1=tx1.cursor()
# cur1.execute( 'update test set x = ? where id = ?', (222, 1) )
#
#
#
#
# # **INSTEAD** of ticket case-1:
# # set transaction read committed no record_version lock timeout N;
# # -- we start Tx with lock_timeout using custom TPB and try just to **update** record which is locked now
# # (but NOT 'SELECT ...'! It is useless with default value of confign parameter ReadConsistency = 1).
# # Message about concurrent transaction (which holds lock) in any case must appear in exception text.
# # NB: NO_rec_version is USELESS in default FB 4.0 config!
#
#
#
#
# # Linsk to doc for creating instance of custom TPB and start transaction which using it:
# # https://pythonhosted.org/fdb/reference.html#fdb.TPB
# # https://pythonhosted.org/fdb/reference.html#fdb.Connection.trans
#
#
# custom_tpb = fdb.TPB()
# custom_tpb.access_mode = fdb.isc_tpb_write
# custom_tpb.isolation_level = (fdb.isc_tpb_read_committed, fdb.isc_tpb_rec_version) # ::: NB ::: NO_rec_version is USELESS in default FB 4.0 config!
# custom_tpb.lock_timeout = 1
#
# tx2 = con.trans( default_tpb = custom_tpb )
#
# tx2 = con.trans( default_tpb = custom_tpb )
# tx2.begin()
# cur2=tx2.cursor()
#
#
# try:
# cur2.execute( 'update test set x = ? where id = ?', (333, 1) )
# except Exception,e:
@ -249,21 +254,21 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
# print( '-'*30 )
# finally:
# tx2.commit()
#
#
# #----------------------------------------------------------
#
#
# # This is for ticket case-2:
# # set transaction read committed lock timeout N;
# # select * from test with lock;
#
# # select * from test with lock;
#
# custom_tpb.access_mode = fdb.isc_tpb_write
# custom_tpb.isolation_level = fdb.isc_tpb_concurrency
# custom_tpb.lock_timeout = 1
#
# tx3 = con.trans( default_tpb = custom_tpb )
#
# tx3 = con.trans( default_tpb = custom_tpb )
# tx3.begin()
# cur3=tx3.cursor()
#
#
# try:
# cur3.execute( 'select x from test where id = ? with lock', (1,) )
# for r in cur3:
@ -276,22 +281,69 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
# print( '-'*30 )
# finally:
# tx3.commit()
#
#
# tx1.commit()
# con.close()
#
#
#
#
#---
#act_2 = python_act('db_2', test_script_2, substitutions=substitutions_2)
act_2 = python_act('db_2', substitutions=substitutions_2)
expected_stdout_2 = """
- concurrent transaction number is 13
- concurrent transaction number is 13
"""
concurrent transaction number is 13
concurrent transaction number is 13
"""
@pytest.mark.version('>=4.0')
@pytest.mark.xfail
def test_2(db_2):
pytest.fail("Test not IMPLEMENTED")
def test_2(act_2: Action, capsys):
with act_2.db.connect() as con:
tx1 = con.transaction_manager()
tx1.begin()
cur1 = tx1.cursor()
cur1.execute('update test set x = ? where id = ?', (222, 1))
# **INSTEAD** of ticket case-1:
# set transaction read committed no record_version lock timeout N;
# -- we start Tx with lock_timeout using custom TPB and try just to **update** record which is locked now
# (but NOT 'SELECT ...'! It is useless with default value of confign parameter ReadConsistency = 1).
# Message about concurrent transaction (which holds lock) in any case must appear in exception text.
# NB: NO_rec_version is USELESS in default FB 4.0 config!
custom_tpb = TPB(access_mode=TraAccessMode.WRITE,
isolation=Isolation.READ_COMMITTED_RECORD_VERSION,
lock_timeout=1)
tx2 = con.transaction_manager(default_tpb=custom_tpb.get_buffer())
tx2.begin()
cur2 = tx2.cursor()
try:
cur2.execute('update test set x = ? where id = ?', (333, 1))
except Exception as e:
print('Exception in cur2:')
print('-' * 30)
for x in e.args:
print(x)
print('-' * 30)
finally:
tx2.commit()
# This is for ticket case-2:
# set transaction read committed lock timeout N;
# select * from test with lock;
custom_tpb.isolation = Isolation.CONCURRENCY
tx3 = con.transaction_manager(default_tpb=custom_tpb.get_buffer())
tx3.begin()
cur3 = tx3.cursor()
try:
cur3.execute('select x from test where id = ? with lock', (1,))
for r in cur3:
print(r[0])
except Exception as e:
print('Exception in cur3:')
print('-' * 30)
for x in e.args:
print(x)
print('-' * 30)
finally:
tx3.commit()
tx1.commit()
act_2.expected_stdout = expected_stdout_2
act_2.stdout = capsys.readouterr().out
assert act_2.clean_stdout == act_2.clean_expected_stdout

View File

@ -2,30 +2,32 @@
#
# id: bugs.core_3008
# title: Add attachment's CHARACTER SET name into corresponding trace records
# decription:
# decription:
# 1. Obtain engine_version from built-in context variable.
# 2. Make config for trace in proper format according to FB engine version,
# with adding invalid element 'foo' instead on boolean ('true' or 'false')
# 3. Launch trace session in separate child process using 'FBSVCMGR action_trace_start'
# 4. Run ISQL single 'QUIT;' command in order trace session will register connection.
# 5. Stop trace session. Output its log with filtering only messages related to connect/disconnect event.
#
#
# Checked on: WI-V2.5.5.26916 (SS, SC, CS); WI-V3.0.0.32008 (SS, SC, CS). Result: OK.
# ::: NB :::
# Several delays (time.sleep) added in main thread because of OS buffering. Couldn't switch this buffering off.
#
#
# tracker_id: CORE-3008
# min_versions: ['2.5.0']
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from threading import Thread
from firebird.qa import db_factory, python_act, Action
# version: 2.5
# resources: None
substitutions_1 = [('^((?!ERROR|ELEMENT|SYSDBA:NONE).)*$', ''), ('.*SYSDBA:NONE', 'SYSDBA:NONE'), ('TCPV.*', 'TCP')]
substitutions_1 = [('^((?!ERROR|ELEMENT|SYSDBA:NONE).)*$', ''),
('.*SYSDBA:NONE', 'SYSDBA:NONE'), ('TCPV.*', 'TCP')]
init_script_1 = """"""
@ -37,32 +39,32 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# import subprocess
# from subprocess import Popen
# import time
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
#
#
# # Obtain engine version, 2.5 or 3.0, for make trace config in appropriate format:
# engine=str(db_conn.engine_version)
# db_conn.close()
#
#
# #---------------------------------------------
#
#
# def flush_and_close(file_handle):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb'):
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
@ -70,9 +72,9 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# os.remove( f_names_list[i] )
# if os.path.isfile( f_names_list[i]):
# print('ERROR: can not remove file ' + f_names_list[i])
#
#
# #--------------------------------------------
#
#
# txt25 = '''# Trace config, format for 2.5. Generated auto, do not edit!
# <database %[\\\\\\\\/]bugs.core_3008.fdb>
# enabled true
@ -80,12 +82,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# log_connections true
# </database>
# '''
#
#
# # NOTES ABOUT TRACE CONFIG FOR 3.0:
# # 1) Header contains `database` clause in different format vs FB 2.5: its data must be enclosed with '{' '}'
# # 2) Name and value must be separated by EQUALITY sign ('=') in FB-3 trace.conf, otherwise we get runtime error:
# # element "<. . .>" have no attribute value set
#
#
# txt30 = '''# Trace config, format for 3.0. Generated auto, do not edit!
# database=%[\\\\\\\\/]bugs.core_3008.fdb
# {
@ -94,38 +96,38 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# log_connections = true
# }
# '''
#
#
# f_trccfg=open( os.path.join(context['temp_directory'],'tmp_trace_3008.cfg'), 'w')
# if engine.startswith('2.5'):
# f_trccfg.write(txt25)
# else:
# f_trccfg.write(txt30)
# f_trccfg.close()
#
#
# #####################################################
# # Starting trace session in new child process (async.):
#
#
# f_trclog = open( os.path.join(context['temp_directory'],'tmp_trace_3008.log'), 'w')
# # Execute a child program in a new process, redirecting STDERR to the same target as of STDOUT:
# p_trace=Popen([context['fbsvcmgr_path'], "localhost:service_mgr",
# "action_trace_start",
# "trc_cfg", f_trccfg.name],
# stdout=f_trclog, stderr=subprocess.STDOUT)
#
#
# # Wait! Trace session is initialized not instantly!
# time.sleep(1)
#
#
# sqltxt='''quit;'''
#
#
# runProgram('isql',[dsn,'-ch','utf8'],sqltxt)
# runProgram('isql',[dsn,'-ch','iso8859_1'],sqltxt)
#
#
# # do NOT remove this otherwise trace log can contain only message about its start before being closed!
# time.sleep(3)
#
#
# #####################################################
# # Getting ID of launched trace session and STOP it:
#
#
# # Save active trace session info into file for further parsing it and obtain session_id back (for stop):
# f_trclst = open( os.path.join(context['temp_directory'],'tmp_trace_3008.lst'), 'w')
# subprocess.call([context['fbsvcmgr_path'], "localhost:service_mgr",
@ -133,7 +135,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout=f_trclst, stderr=subprocess.STDOUT
# )
# flush_and_close( f_trclst )
#
#
# trcssn=0
# with open( f_trclst.name,'r') as f:
# for line in f:
@ -144,7 +146,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# trcssn=word
# i=i+1
# break
#
#
# # Result: `trcssn` is ID of active trace session. Now we have to terminate it:
# f_trclst=open(f_trclst.name,'a')
# f_trclst.seek(0,2)
@ -154,40 +156,66 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout=f_trclst, stderr=subprocess.STDOUT
# )
# flush_and_close( f_trclst )
#
#
# # Terminate child process of launched trace session (though it should already be killed):
# p_trace.terminate()
#
#
# flush_and_close( f_trclog )
#
#
#
#
# # Output log of trace for comparing it with expected: it must contain only TWO events: TRACE_INIT and TRACE_FINI
# # ::: NB ::: Content if trace log is converted to UPPER case in order to reduce change of mismatching with
# # updated trace output in some future versions:
# with open( f_trclog.name,'r') as f:
# print(f.read().upper())
#
#
#
#
# # do NOT remove this delay otherwise get access error 'Windows 32'
# # (The process cannot access the file because it is being used by another process):
# time.sleep(1)
#
#
# cleanup( [i.name for i in (f_trccfg, f_trclst, f_trclog ) ] )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
SYSDBA:NONE, UTF8, TCP
SYSDBA:NONE, UTF8, TCP
SYSDBA:NONE, ISO88591, TCP
SYSDBA:NONE, ISO88591, TCP
"""
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
"""
def trace_session(act: Action):
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
f'database=%[\\\\/]{act.db.db_path.name}',
'{',
' enabled = true',
' log_connections = true',
' time_threshold = 0',
'}']
with act.connect_server() as srv:
srv.trace.start(config='\n'.join(cfg30))
for line in srv:
print(line.upper())
@pytest.mark.version('>=3.0')
def test_1(act_1: Action, capsys):
trace_thread = Thread(target=trace_session, args=[act_1])
trace_thread.start()
# make two connections with different charset
with act_1.db.connect(charset='utf8'):
pass
with act_1.db.connect(charset='iso8859_1'):
pass
with act_1.connect_server() as srv:
for session in list(srv.trace.sessions.keys()):
srv.trace.stop(session_id=session)
trace_thread.join(1.0)
if trace_thread.is_alive():
pytest.fail('Trace thread still alive')
act_1.expected_stdout = expected_stdout_1
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,18 +2,18 @@
#
# id: bugs.core_3024
# title: Error "no current record for fetch operation" after ALTER VIEW
# decription:
# decription:
# Confirmed error on: WI-V2.5.6.26962 (SC), fixed on: WI-V2.5.6.26963.
# Checked on WI-V3.0.0.32268 (SS, SC, CS).
# Checked on fdb version 1.5.
#
#
# tracker_id: CORE-3024
# min_versions: ['2.5.6']
# versions: 2.5.6
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 2.5.6
# resources: None
@ -27,44 +27,61 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# test_script_1
#---
# db_conn.close()
#
#
# att1=kdb.connect(dsn=dsn.encode(),user='SYSDBA',password='masterkey')
# att2=kdb.connect(dsn=dsn.encode(),user='SYSDBA',password='masterkey')
#
#
# trn1=att1.trans()
#
#
# cur1=trn1.cursor()
#
#
# cur1.execute("create table t(a int, b int, c int)") # att_12, tra_4
# cur1.execute("create view v as select a,b from t")
# trn1.commit()
#
#
# cur1.execute("insert into t values(1,2,3)") # att_12, tra_5
# cur1.execute("select * from v")
# trn1.commit()
#
#
# trn2=att2.trans()
# cur2=trn2.cursor()
# cur2.execute("select * from v") # att_13, tra_7
# trn2.commit()
#
#
# cur1.execute("alter view v as select a, b, c from t") # att-12, tra_8
# trn1.commit()
#
#
# cur2.execute("select * from v") # att_13, tra_9
# printData(cur2)
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
A B C
1 2 3
"""
"""
@pytest.mark.version('>=2.5.6')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, capsys):
with act_1.db.connect() as att1, act_1.db.connect() as att2:
trn1 = att1.transaction_manager()
cur1 = trn1.cursor()
cur1.execute("create table t(a int, b int, c int)") # att_12, tra_4
cur1.execute("create view v as select a,b from t")
trn1.commit()
cur1.execute("insert into t values(1,2,3)") # att_12, tra_5
cur1.execute("select * from v")
trn1.commit()
trn2 = att2.transaction_manager()
cur2 = trn2.cursor()
cur2.execute("select * from v") # att_13, tra_7
trn2.commit()
cur1.execute("alter view v as select a, b, c from t") # att-12, tra_8
trn1.commit()
cur2.execute("select * from v") # att_13, tra_9
act_1.print_data(cur2)
act_1.expected_stdout = expected_stdout_1
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,23 +2,23 @@
#
# id: bugs.core_3095
# title: Client receive event's with count equal to 1 despite of how many times EVENT was POSTed in same transaction
# decription:
# decription:
# We create stored procedure as it was specified in the ticket, and call it with input arg = 3.
# This mean that we have to receive THREE events after code which calls this SP will issue COMMIT.
#
#
# Confirmed on 2.5.0.26074 - only one event was delivered instead of three.
# Works OK since 2.5.1.26351.
#
# PS. Event handling code in this text was adapted from fdb manual:
#
# PS. Event handling code in this text was adapted from fdb manual:
# http://pythonhosted.org/fdb/usage-guide.html#database-events
#
#
# tracker_id: CORE-3095
# min_versions: ['2.5.1']
# versions: 2.5.1
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from firebird.qa import db_factory, python_act, Action
# version: 2.5.1
# resources: None
@ -38,7 +38,7 @@ init_script_1 = """
^
set term ;^
commit;
"""
"""
db_1 = db_factory(sql_dialect=3, init=init_script_1)
@ -46,55 +46,61 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
#---
# import os
# import threading
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# # Utility function
# def send_events(command_list):
# cur = db_conn.cursor()
# for cmd in command_list:
# cur.execute(cmd)
# db_conn.commit()
#
#
# timed_event = threading.Timer(3.0, send_events, args=[["execute procedure sp_test(3)",]])
#
# # Connection.event_conduit() takes a sequence of string event names as parameter, and returns
#
# # Connection.event_conduit() takes a sequence of string event names as parameter, and returns
# # EventConduit instance.
# events = db_conn.event_conduit(['loop'])
#
# # To start listening for events it's necessary (starting from FDB version 1.4.2)
#
# # To start listening for events it's necessary (starting from FDB version 1.4.2)
# # to call EventConduit.begin() method or use EventConduit's context manager interface
# # Immediately when begin() method is called, EventConduit starts to accumulate notifications
# # of any events that occur within the conduit's internal queue until the conduit is closed
# # Immediately when begin() method is called, EventConduit starts to accumulate notifications
# # of any events that occur within the conduit's internal queue until the conduit is closed
# # (via the close() method)
#
#
# events.begin()
#
#
# timed_event.start()
#
# # Notifications about events are aquired through call to wait() method, that blocks the calling
# # thread until at least one of the events occurs, or the specified timeout (if any) expires,
#
# # Notifications about events are aquired through call to wait() method, that blocks the calling
# # thread until at least one of the events occurs, or the specified timeout (if any) expires,
# # and returns None if the wait timed out, or a dictionary that maps event_name -> event_occurrence_count.
#
#
# e = events.wait(10)
#
#
# events.close()
#
#
# print(e)
# db_conn.close()
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
{'loop': 3}
"""
@pytest.mark.version('>=2.5.1')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
{'loop': 3}
"""
@pytest.mark.version('>=3.0')
def test_1(act_1: Action, capsys):
act_1.expected_stdout = expected_stdout_1
with act_1.db.connect() as con:
c = con.cursor()
with con.event_collector(['loop']) as events:
c.execute('execute procedure sp_test(3)')
con.commit()
print(events.wait(10))
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,7 +2,7 @@
#
# id: bugs.core_3131
# title: WIN1257_LV (Latvian) collation is wrong for 4 letters: A E I U.
# decription:
# decription:
# ::: NOTE :::
# In order to check correctness of following statements under ISQL itself (NOT under fbt_run), do following:
# 1) open some text editor that supports charset = win1257 and set encoding for new document = WIN1257
@ -19,27 +19,28 @@
# 4) save .fbt and ensure that it was saved in UTF8 encoding, otherwise exeption like
# "UnicodeDecodeError: 'utf8' codec can't decode byte 0xc3 in position 621: invalid continuation byte"
# will raise.
#
#
# 05-mar-2021. Re-implemented in order to have ability to run this test on Linux.
# Test encodes to UTF8 all needed statements (SET NAMES; CONNECT; DDL and DML) and stores this text in .sql file.
# NOTE: 'SET NAMES' contain character set that must be used for reproducing problem (WIN1257 in this test).
# Then ISQL is launched in separate (child) process which performs all necessary actions (using required charset).
# Result will be redirected to log(s) which will be opened further via codecs.open(...encoding='cp1257').
# Finally, its content will be converted to UTF8 for showing in expected_stdout.
#
#
# Confirmed bug on 2.5.0.26074. Fixed on 2.5.1.26351 and up to 2.5.9.27152
#
#
# Checked on:
# * Windows: 4.0.0.2377, 3.0.8.33423
# * Linux: 4.0.0.2379, 3.0.8.33415
#
#
# tracker_id: CORE-3131
# min_versions: ['2.5.0']
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from pathlib import Path
from firebird.qa import db_factory, python_act, Action, temp_file
# version: 2.5
# resources: None
@ -52,31 +53,31 @@ db_1 = db_factory(charset='WIN1257', sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
#
# import os
# import codecs
# import subprocess
# import time
# engine = db_conn.engine_version
# db_conn.close()
#
#
# #--------------------------------------------
#
#
# def flush_and_close( file_handle ):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
@ -87,43 +88,43 @@ db_1 = db_factory(charset='WIN1257', sql_dialect=3, init=init_script_1)
# else:
# print('Unrecognized type of element:', f_names_list[i], ' - can not be treated as file.')
# del_name = None
#
#
# if del_name and os.path.isfile( del_name ):
# os.remove( del_name )
#
#
# #--------------------------------------------
#
#
# sql_txt=''' set bail on;
# set names win1257;
# connect '%(dsn)s' user '%(user_name)s' password '%(user_password)s';
#
#
# create collation coll_1257_ci_ai
# for win1257 from win1257_lv
# no pad case insensitive accent sensitive;
# commit;
#
#
# create table test1257 (
# letter varchar(2) collate coll_1257_ci_ai,
# sort_index smallint
# );
#
#
# -- ### ONCE AGAIN ###
# -- 1) for checking this under ISQL following must be encoded in WIN1257
# -- 2) for running under fbt_run utility following must be encoded in UTF8.
# insert into test1257 values ('Iz', 18);
# insert into test1257 values ('Īb', 19);
# insert into test1257 values ('Īz', 20);
#
#
# insert into test1257 values ('Ķz', 24);
# insert into test1257 values ('Ēz', 12);
# insert into test1257 values ('Gb', 13);
#
#
# insert into test1257 values ('Ģz', 16);
# insert into test1257 values ('Ib', 17);
#
#
# insert into test1257 values ('Gz', 14);
# insert into test1257 values ('Ģb', 15);
#
#
# insert into test1257 values ('Ņb', 31);
# insert into test1257 values ('Ņz', 32);
# insert into test1257 values ('Cb', 5);
@ -133,10 +134,10 @@ db_1 = db_factory(charset='WIN1257', sql_dialect=3, init=init_script_1)
# insert into test1257 values ('Eb', 9);
# insert into test1257 values ('Ez', 10);
# insert into test1257 values ('Ēb', 11);
#
#
# insert into test1257 values ('Ub', 37);
# insert into test1257 values ('Uz', 38);
#
#
# insert into test1257 values ('Lz', 26);
# insert into test1257 values ('Ļb', 27);
# insert into test1257 values ('Ļz', 28);
@ -147,108 +148,195 @@ db_1 = db_factory(charset='WIN1257', sql_dialect=3, init=init_script_1)
# insert into test1257 values ('Cz', 6);
# insert into test1257 values ('Čb', 7);
# insert into test1257 values ('Čz', 8);
#
#
# insert into test1257 values ('Sb', 33);
# insert into test1257 values ('Sz', 34);
# insert into test1257 values ('Šb', 35);
#
#
# insert into test1257 values ('Nb', 29);
# insert into test1257 values ('Nz', 30);
# insert into test1257 values ('Ķb', 23);
# insert into test1257 values ('Zz', 42);
# insert into test1257 values ('Žb', 43);
# insert into test1257 values ('Žz', 44);
#
#
# insert into test1257 values ('Ab', 1);
# insert into test1257 values ('Az', 2);
# insert into test1257 values ('Āb', 3);
# insert into test1257 values ('Āz', 4);
# insert into test1257 values ('Āz', 4);
# commit;
#
#
# set heading off;
# select *
# from test1257 tls
# order by tls.letter collate coll_1257_ci_ai;
#
#
# ''' % dict(globals(), **locals())
#
#
# f_run_sql = open( os.path.join(context['temp_directory'], 'tmp_3131_win1257.sql'), 'w' )
# f_run_sql.write( sql_txt.decode('utf8').encode('cp1257') )
# flush_and_close( f_run_sql )
#
#
# # result: file tmp_3131_win1257.sql is encoded in win1257
#
#
# f_run_log = open( os.path.splitext(f_run_sql.name)[0]+'.log', 'w')
# subprocess.call( [ context['isql_path'], '-q', '-i', f_run_sql.name ],
# stdout = f_run_log,
# stderr = subprocess.STDOUT
# )
# flush_and_close( f_run_log ) # result: output will be encoded in win1257
#
#
# with codecs.open(f_run_log.name, 'r', encoding='cp1257' ) as f:
# result_in_win1257 = f.readlines()
#
#
# for i in result_in_win1257:
# print( i.encode('utf8') )
#
#
# # cleanup:
# ###########
# cleanup( (f_run_sql, f_run_log) )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
test_script_1 = """
set bail on;
set names win1257;
create collation coll_1257_ci_ai
for win1257 from win1257_lv
no pad case insensitive accent sensitive;
commit;
create table test1257 (
letter varchar(2) collate coll_1257_ci_ai,
sort_index smallint
);
commit;
-- ### ONCE AGAIN ###
-- 1) for checking this under ISQL following must be encoded in WIN1257
-- 2) for running under fbt_run utility following must be encoded in UTF8.
insert into test1257 values ('Iz', 18);
insert into test1257 values ('Īb', 19);
insert into test1257 values ('Īz', 20);
insert into test1257 values ('Ķz', 24);
insert into test1257 values ('Ēz', 12);
insert into test1257 values ('Gb', 13);
insert into test1257 values ('Ģz', 16);
insert into test1257 values ('Ib', 17);
insert into test1257 values ('Gz', 14);
insert into test1257 values ('Ģb', 15);
insert into test1257 values ('Ņb', 31);
insert into test1257 values ('Ņz', 32);
insert into test1257 values ('Cb', 5);
insert into test1257 values ('Ūb', 39);
insert into test1257 values ('Ūz', 40);
insert into test1257 values ('Zb', 41);
insert into test1257 values ('Eb', 9);
insert into test1257 values ('Ez', 10);
insert into test1257 values ('Ēb', 11);
insert into test1257 values ('Ub', 37);
insert into test1257 values ('Uz', 38);
insert into test1257 values ('Lz', 26);
insert into test1257 values ('Ļb', 27);
insert into test1257 values ('Ļz', 28);
insert into test1257 values ('Kb', 21);
insert into test1257 values ('Kz', 22);
insert into test1257 values ('Šz', 36);
insert into test1257 values ('Lb', 25);
insert into test1257 values ('Cz', 6);
insert into test1257 values ('Čb', 7);
insert into test1257 values ('Čz', 8);
insert into test1257 values ('Sb', 33);
insert into test1257 values ('Sz', 34);
insert into test1257 values ('Šb', 35);
insert into test1257 values ('Nb', 29);
insert into test1257 values ('Nz', 30);
insert into test1257 values ('Ķb', 23);
insert into test1257 values ('Zz', 42);
insert into test1257 values ('Žb', 43);
insert into test1257 values ('Žz', 44);
insert into test1257 values ('Ab', 1);
insert into test1257 values ('Az', 2);
insert into test1257 values ('Āb', 3);
insert into test1257 values ('Āz', 4);
commit;
set heading off;
select *
from test1257 tls
order by tls.letter collate coll_1257_ci_ai;
"""
expected_stdout_1 = """
Ab 1
Az 2
Āb 3
Āz 4
Cb 5
Cz 6
Čb 7
Čz 8
Eb 9
Ez 10
Ēb 11
Ēz 12
Gb 13
Gz 14
Ģb 15
Ģz 16
Ib 17
Iz 18
Īb 19
Īz 20
Kb 21
Kz 22
Ķb 23
Ķz 24
Lb 25
Lz 26
Ļb 27
Ļz 28
Nb 29
Nz 30
Ņb 31
Ņz 32
Sb 33
Sz 34
Šb 35
Šz 36
Ub 37
Uz 38
Ūb 39
Ūz 40
Zb 41
Zz 42
Žb 43
Žz 44
Ab 1
Az 2
Āb 3
Āz 4
Cb 5
Cz 6
Čb 7
Čz 8
Eb 9
Ez 10
Ēb 11
Ēz 12
Gb 13
Gz 14
Ģb 15
Ģz 16
Ib 17
Iz 18
Īb 19
Īz 20
Kb 21
Kz 22
Ķb 23
Ķz 24
Lb 25
Lz 26
Ļb 27
Ļz 28
Nb 29
Nz 30
Ņb 31
Ņz 32
Sb 33
Sz 34
Šb 35
Šz 36
Ub 37
Uz 38
Ūb 39
Ūz 40
Zb 41
Zz 42
Žb 43
Žz 44
"""
script_file = temp_file('test-script.sql')
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, script_file: Path):
script_file.write_text(test_script_1, encoding='cp1257')
act_1.expected_stdout = expected_stdout_1
act_1.isql(switches=[], input_file=script_file, charset='WIN1257')
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,38 +2,41 @@
#
# id: bugs.core_3168
# title: exclude_filter doesn't work for <services></section> section of the Trace facility
# decription:
# decription:
# Note. It was encountered that FBSVCMGR does NOT wait for OS completes writing of its output on disk,
# (see CORE-4896), so we use delays - see calls of time.sleep().
#
#
# Correct work was checked on: WI-V2.5.5.26916 (SS, SC) and WI-V3.0.0.31948 (SS, SC, CS)
# Refactored 17.12.2016 after encountering CORE-5424 ("restore process is impossible when trace ..."):
# added checking of STDERR logs for all fbsvcmgr actions.
#
#
# -----------------------------------------
# Updated 27.03.2017: moved artificial delay (1 sec) at proper place.
# It should be just after
# subprocess.call('fbsvcmgr', 'localhost:service_mgr', 'action_trace_stop', ...)
# and BEFORE 'p_trace.terminate()' command.
# -----------------------------------------
#
#
# Test time (approx):
# 2.5.7.27030: SC = 3"
# 2.5.7.27030: SC = 3"
# 3.0.232644 and 4.0.0.463: SS = SC = 6"; CS = 15"
# Checked on 2.5.8.27056, CLASSIC server: 3.6" (27-03-2017)
#
#
# 13.04.2021. Adapted for run both on Windows and Linux. Checked on:
# Windows: 3.0.8.33445, 4.0.0.2416
# Linux: 3.0.8.33426, 4.0.0.2416
#
#
#
#
# tracker_id: CORE-3168
# min_versions: ['2.5.0']
# versions: 2.5
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from threading import Thread, Barrier
from io import BytesIO
from firebird.qa import db_factory, python_act, Action, temp_file
from firebird.driver import SrvStatFlag
# version: 2.5
# resources: None
@ -46,37 +49,37 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
#
# import os
# import subprocess
# import time
# from fdb import services
# from subprocess import Popen
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# # Obtain engine version:
# engine = str(db_conn.engine_version) # convert to text because 'float' object has no attribute 'startswith'
# db_conn.close()
#
#
# #--------------------------------------------
#
#
# def flush_and_close( file_handle ):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
@ -88,13 +91,13 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# print('Unrecognized type of element:', f_names_list[i], ' - can not be treated as file.')
# print('type(f_names_list[i])=',type(f_names_list[i]))
# del_name = None
#
#
# if del_name and os.path.isfile( del_name ):
# os.remove( del_name )
#
#
# #--------------------------------------------
#
#
#
#
# # ::: NB ::: Trace config file format in 3.0 differs from 2.5 one:
# # 1) header section must be enclosed in "[" and "]",
# # 2) parameter-value pairs must be separated with '=' sign:
@ -102,16 +105,16 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# # {
# # parameter = value
# # }
#
#
# if engine.startswith('2.5'):
# txt = '''# Generated auto, do not edit!
# <services>
# enabled true
# log_services true
#
#
# # This should prevent appearance of messages like "List Trace Session(s)" or "Start Trace Session(s)":
# exclude_filter "%(List|LIST|list|Start|START|start)[[:WHITESPACE:]]+(Trace|TRACE|trace)[[:WHITESPACE:]]+(Session|SESSION|session)%"
#
#
# # This should work even if we filter out messages about list/start trace session(s)
# # (and test also check corret work of THIS filter beside previous `exclude`):
# # include_filter "Database Stats"
@ -123,68 +126,68 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# {
# enabled = true
# log_services = true
#
#
# # This should prevent appearance of messages like "List Trace Session(s)" or "Start Trace Session(s)":
# exclude_filter = "%(List|LIST|list|Start|START|start)[[:WHITESPACE:]]+(Trace|TRACE|trace)[[:WHITESPACE:]]+(Session|SESSION|session)%"
#
#
# # This should work even if we filter out messages about list/start trace session(s)
# # (and test also check corret work of THIS filter beside previous `exclude`):
# # include_filter = "Database Stats"
# }
# '''
#
#
# f_trc_cfg=open( os.path.join(context['temp_directory'],'tmp_trace_3168.cfg'), 'w')
# f_trc_cfg.write(txt)
# f_trc_cfg.close()
#
#
# # Instead of using 'start /min cmd /c fbsvcmgr ... 1>%2 2>&1' deciced to exploite Popen in order to run asynchronous process
# # without opening separate window. Output is catched into `trclog` file, which will be closed after call fbsvcmgr with argument
# # 'action_trace_stop' (see below):
# # See also:
# # https://docs.python.org/2/library/subprocess.html
# # http://stackoverflow.com/questions/11801098/calling-app-from-subprocess-call-with-arguments
#
#
# # ##############################################################
# # S T A R T T R A C E i n S E P A R A T E P R O C E S S
# # ##############################################################
#
#
# f_trc_log=open( os.path.join(context['temp_directory'],'tmp_trace_3168.log'), "w")
# f_trc_err=open( os.path.join(context['temp_directory'],'tmp_trace_3168.err'), "w")
#
#
# p_trace = Popen([ context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_trace_start' , 'trc_cfg', f_trc_cfg.name],stdout=f_trc_log,stderr=f_trc_err)
#
#
# thisdb='$(DATABASE_LOCATION)bugs.core_3168.fdb'
# tmpbkp='$(DATABASE_LOCATION)bugs.core_3168_fbk.tmp'
# tmpres='$(DATABASE_LOCATION)bugs.core_3168_new.tmp'
#
#
# f_run_log=open( os.path.join(context['temp_directory'],'tmp_action_3168.log'), 'w')
# f_run_err=open( os.path.join(context['temp_directory'],'tmp_action_3168.err'), 'w')
#
#
# subprocess.call( [ context['fbsvcmgr_path'], 'localhost:service_mgr','action_properties','dbname', thisdb,'prp_sweep_interval', '1234321'], stdout=f_run_log,stderr=f_run_err)
# subprocess.call( [ context['fbsvcmgr_path'], 'localhost:service_mgr','action_db_stats', 'dbname', thisdb, 'sts_hdr_pages'], stdout=f_run_log,stderr=f_run_err)
# subprocess.call( [ context['fbsvcmgr_path'], 'localhost:service_mgr','action_backup', 'dbname', thisdb, 'bkp_file', tmpbkp], stdout=f_run_log,stderr=f_run_err)
# subprocess.call( [ context['fbsvcmgr_path'], 'localhost:service_mgr','action_restore', 'bkp_file', tmpbkp, 'dbname', tmpres, 'res_replace'], stdout=f_run_log,stderr=f_run_err)
#
#
# flush_and_close( f_run_log )
# flush_and_close( f_run_err )
#
#
# # do NOT try to get FB log! It can contain non-ascii messages which lead to runtime fault of fbtest!
# # (see CORE-5418):
# # runProgram(context['fbsvcmgr_path'],['localhost:service_mgr','action_get_fb_log'])
#
#
#
#
# # ####################################################
# # G E T A C T I V E T R A C E S E S S I O N I D
# # ####################################################
# # Save active trace session info into file for further parsing it and obtain session_id back (for stop):
#
#
# f_trc_lst = open( os.path.join(context['temp_directory'],'tmp_trace_3168.lst'), 'w')
# subprocess.call([context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_trace_list'], stdout=f_trc_lst)
# flush_and_close( f_trc_lst )
#
#
# # !!! DO NOT REMOVE THIS LINE !!!
# time.sleep(1)
#
#
# trcssn=0
# with open( f_trc_lst.name,'r') as f:
# for line in f:
@ -196,76 +199,109 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# i=i+1
# break
# # Result: `trcssn` is ID of active trace session. Now we have to terminate it:
#
#
# # ####################################################
# # S E N D R E Q U E S T T R A C E T O S T O P
# # ####################################################
#
#
# fn_nul = open(os.devnull, 'w')
# subprocess.call([context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_trace_stop','trc_id', trcssn], stdout=fn_nul)
# fn_nul.close()
#
#
# # ::: NB ::: Artificial delay, Added 27.03.2017.
# # Do NOT remove this line otherwise record with 'database restore' may not appear
# # Do NOT remove this line otherwise record with 'database restore' may not appear
# # in the final trace log (file buffer is flushed not instantly).
# time.sleep(1)
#
#
# time.sleep(1)
#
#
# # Doc about Popen.terminate():
# # https://docs.python.org/2/library/subprocess.html
# # Stop the child. On Posix OSs the method sends SIGTERM to the child.
# # On Windows the Win32 API function TerminateProcess() is called to stop the child.
#
#
# # Doc about Win API TerminateProcess() function:
# # https://msdn.microsoft.com/en-us/library/windows/desktop/ms686714%28v=vs.85%29.aspx
# # The terminated process cannot exit until all pending I/O has been completed or canceled.
# # TerminateProcess is ____asynchronous____; it initiates termination and returns immediately.
# # ^^^^^^^^^^^^
#
#
# p_trace.terminate()
# flush_and_close(f_trc_log)
# flush_and_close(f_trc_err)
#
#
# # Should be EMPTY:
# with open( f_trc_err.name,'r') as f:
# for line in f:
# if line.split():
# print('fbsvcmgr(1) unexpected STDERR: '+line.upper() )
#
#
# # Should be EMPTY:
# with open( f_run_err.name,'r') as f:
# for line in f:
# if line.split():
# print('fbsvcmgr(2) unexpected STDERR: '+line.upper() )
#
#
# # Output log of trace for comparing it with expected.
# # ::: NB ::: Content if trace log is converted to UPPER case in order to reduce change of mismatching with
# # updated trace output in some future versions:
#
#
# with open( f_trc_log.name,'r') as f:
# for line in f:
# if line.split():
# print(line.upper())
#
#
# # CLEANUP
# #########
# time.sleep(1)
# cleanup( (f_trc_cfg, f_trc_lst, f_trc_log, f_trc_err, f_run_log, f_run_err, tmpbkp, tmpres) )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
"DATABASE PROPERTIES"
"DATABASE STATS"
"BACKUP DATABASE"
"RESTORE DATABASE"
"""
EXCLUDE_FILTER = "DATABASE STATS"
"DATABASE PROPERTIES"
"BACKUP DATABASE"
"""
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def trace_session(act: Action, barrier: Barrier):
cfg30 = ['services',
'{',
' enabled = true',
' log_services = true',
' exclude_filter = "Database Stats"',
'}']
with act.connect_server() as srv:
srv.trace.start(config='\n'.join(cfg30))
barrier.wait()
for line in srv:
print(line.upper())
temp_file_1 = temp_file('test-file')
@pytest.mark.version('>=3.0')
def test_1(act_1: Action, capsys, temp_file_1):
b = Barrier(2)
trace_thread = Thread(target=trace_session, args=[act_1, b])
trace_thread.start()
with act_1.connect_server() as srv:
# Make some service requests
b.wait()
srv.database.set_sweep_interval(database=str(act_1.db.db_path), interval=1234321)
srv.database.get_statistics(database=str(act_1.db.db_path), flags=SrvStatFlag.HDR_PAGES)
srv.wait()
srv.database.backup(database=str(act_1.db.db_path), backup=str(temp_file_1))
srv.wait()
#
for session in list(srv.trace.sessions.keys()):
srv.trace.stop(session_id=session)
trace_thread.join(2.0)
if trace_thread.is_alive():
pytest.fail('Trace thread still alive')
act_1.expected_stdout = expected_stdout_1
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -2,7 +2,7 @@
#
# id: bugs.core_3188
# title: page 0 is of wrong type (expected 6, found 1)
# decription:
# decription:
# Confirmed on WI-V2.5.0.26074
# exception:
# DatabaseError:
@ -13,21 +13,22 @@
# - page 0 is of wrong type (expected 6, found 1)
# -902
# 335544335
#
#
# New messages in firebird.log in 2.5.0 after running ticket statements:
#
#
# CSPROG (Client) Mon Feb 15 07:28:05 2016
# INET/inet_error: connect errno = 10061
# CSPROG Mon Feb 15 07:41:02 2016
# Shutting down the server with 0 active connection(s) to 0 database(s), 1 active service(s)
#
#
# tracker_id: CORE-3188
# min_versions: ['2.5.1']
# versions: 2.5.1
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from difflib import unified_diff
from firebird.qa import db_factory, python_act, Action
# version: 2.5.1
# resources: None
@ -40,34 +41,34 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# test_script_1
#---
#
#
# import os
# import difflib
#
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
#
# engine = str(db_conn.engine_version)
# db_conn.close()
#
#
#
#
# #---------------------------------------------
#
#
# def flush_and_close(file_handle):
# # https://docs.python.org/2/library/os.html#os.fsync
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # If you're starting with a Python file object f,
# # first do f.flush(), and
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
#
#
# file_handle.flush()
# if file_handle.mode not in ('r', 'rb'):
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
# os.fsync(file_handle.fileno())
# file_handle.close()
#
#
# #--------------------------------------------
#
#
# def cleanup( f_names_list ):
# global os
# for i in range(len( f_names_list )):
@ -75,20 +76,20 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# os.remove( f_names_list[i] )
# if os.path.isfile( f_names_list[i]):
# print('ERROR: can not remove file ' + f_names_list[i])
#
#
# #--------------------------------------------
#
#
# def svc_get_fb_log( engine, f_fb_log ):
#
#
# import subprocess
#
#
# # ::: NB ::: Service call for receive firebird.log works properly only since FB 2.5.2!
#
#
# if engine.startswith('2.5'):
# get_firebird_log_key='action_get_ib_log'
# else:
# get_firebird_log_key='action_get_fb_log'
#
#
# subprocess.call([ context['fbsvcmgr_path'],
# "localhost:service_mgr",
# get_firebird_log_key
@ -96,73 +97,83 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# stdout=f_fb_log, stderr=subprocess.STDOUT
# )
# return
#
#
# #--------------------------------------------
#
#
#
#
# # Start two attachments:
# con1 = kdb.connect(dsn=dsn)
# con2 = kdb.connect(dsn=dsn)
#
#
# # Session-1:
# c1 = con1.cursor()
#
#
#
#
# f_fblog_before=open( os.path.join(context['temp_directory'],'tmp_3188_fblog_before.txt'), 'w')
# svc_get_fb_log( engine, f_fblog_before )
# flush_and_close( f_fblog_before )
#
#
# c1.execute("create table test(id int primary key)")
# con1.commit()
#
#
# # Session-2:
#
#
# c2 = con2.cursor()
# c2.execute('drop table test')
# con2.commit()
#
#
# # cleanup
# con1.close()
# con2.close()
#
#
# f_fblog_after=open( os.path.join(context['temp_directory'],'tmp_3188_fblog_after.txt'), 'w')
# svc_get_fb_log( engine, f_fblog_after )
# flush_and_close( f_fblog_after )
#
#
# # Now we can compare two versions of firebird.log and check their difference.
#
#
# oldfb=open(f_fblog_before.name, 'r')
# newfb=open(f_fblog_after.name, 'r')
#
#
# difftext = ''.join(difflib.unified_diff(
# oldfb.readlines(),
# oldfb.readlines(),
# newfb.readlines()
# ))
# oldfb.close()
# newfb.close()
#
#
# f_diff_txt=open( os.path.join(context['temp_directory'],'tmp_3188_diff.txt'), 'w')
# f_diff_txt.write(difftext)
# flush_and_close( f_diff_txt )
#
#
# # Difference of firebird.log should be EMPTY:
#
#
# with open( f_diff_txt.name,'r') as f:
# print( f.read() )
# f.close()
#
#
# ###############################
# # Cleanup.
# cleanup( [i.name for i in (f_fblog_before, f_fblog_after, f_diff_txt)] )
#
#
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=2.5.1')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
with act_1.connect_server() as srv:
srv.info.get_log()
log_before = srv.readlines()
with act_1.db.connect() as con1, act_1.db.connect() as con2:
c1 = con1.cursor()
c1.execute("create table test(id int primary key)")
con1.commit()
#
c2 = con2.cursor()
c2.execute('drop table test')
con2.commit()
srv.info.get_log()
log_after = srv.readlines()
assert list(unified_diff(log_before, log_after)) == []