diff --git a/tests/bugs/core_0210_test.py b/tests/bugs/core_0210_test.py index f770d7bf..8ed383c9 100644 --- a/tests/bugs/core_0210_test.py +++ b/tests/bugs/core_0210_test.py @@ -2,15 +2,16 @@ # # id: bugs.core_0210 # title: CS server crash altering SP in 2 connect -# decription: -# +# decription: +# # tracker_id: CORE-0210 # 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 +from firebird.driver import TPB, Isolation # version: 2.5 # resources: None @@ -23,15 +24,15 @@ db_1 = db_factory(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() -# +# # stm1='''create or alter procedure sp_test as # begin # exit; @@ -43,38 +44,63 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # exit; # end # ''' -# +# # con1 = fdb.connect(dsn=dsn) # con2 = fdb.connect(dsn=dsn) -# +# # xtpb = ( [ fdb.isc_tpb_concurrency ] ) -# +# # con1.begin( tpb = xtpb ) -# +# # cur1=con1.cursor() # cur2=con2.cursor() -# +# # cur1.execute(stm1) # con1.commit() -# +# # con2.begin( tpb = xtpb ) # cur2.execute(stm2) # con2.commit() -# +# # con1.begin( tpb = xtpb ) # cur1.execute(stm1) # con1.commit() -# +# # con1.close() # con2.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): + stm1 = '''create or alter procedure sp_test as + begin + exit; + end + ''' + stm2 = '''create or alter procedure sp_test as + declare x int; + begin + exit; + end + ''' + tpb = TPB(isolation=Isolation.CONCURRENCY).get_buffer() + with act_1.db.connect() as con1, act_1.db.connect() as con2: + con1.begin(tpb) + cur1 = con1.cursor() + cur2 = con2.cursor() + + cur1.execute(stm1) + con1.commit() + + con2.begin(tpb) + cur2.execute(stm2) + con2.commit() + + con1.begin(tpb) + cur1.execute(stm1) + con1.commit() diff --git a/tests/bugs/core_0216_test.py b/tests/bugs/core_0216_test.py index 8f05b622..dfadad91 100644 --- a/tests/bugs/core_0216_test.py +++ b/tests/bugs/core_0216_test.py @@ -11,7 +11,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 @@ -38,7 +38,7 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1) # c.execute(cmd % i) # i += 1 # db_conn.commit() -# +# # # Grants # i = 1 # cmd = """GRANT INSERT ON LOG TO TRIGGER LOGT_%d""" @@ -51,12 +51,30 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1) # i += 1 # db_conn.commit() #--- -#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 con: + c = con.cursor() + # Create 4000 triggers on table T + i = 1 + cmd = """create trigger LOGT_%d for T after insert as + begin + insert into log (PK) values (new.pk); + end + """ + while i <= 4000: + c.execute(cmd % i) + i += 1 + con.commit() + # Grants + i = 1 + cmd = """GRANT INSERT ON LOG TO TRIGGER LOGT_%d""" + while i <= 4000: + c.execute(cmd % i) + i += 1 + con.commit() diff --git a/tests/bugs/core_0337_test.py b/tests/bugs/core_0337_test.py index 825a3f7b..e53f8d63 100644 --- a/tests/bugs/core_0337_test.py +++ b/tests/bugs/core_0337_test.py @@ -2,22 +2,22 @@ # # id: bugs.core_0337 # title: bug #910430 ISQL and database dialect -# decription: -# ::: NB ::: +# decription: +# ::: NB ::: # ### Name of original test has no any relation with actual task of this test: ### # https://github.com/FirebirdSQL/fbtcs/blob/master/GTCS/tests/CF_ISQL_25.script -# +# # When ISQL disconnects from database (either by dropping it or by trying to connect to # non-existent database) is still remembers its sql dialect, which can lead to some # inappropriate warning messages. -# +# # Issue in original script: bug #910430 ISQL and database dialect # Found in FB tracker as: http://tracker.firebirdsql.org/browse/CORE-337 # Fixed in 2.0 Beta 1 -# +# # Checked on: 4.0.0.1803 SS; 3.0.6.33265 SS; 2.5.9.27149 SC. -# -# tracker_id: +# +# tracker_id: # min_versions: ['2.5.0'] # versions: 2.5 # qmid: None @@ -36,112 +36,137 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # test_script_1 #--- -# +# # import os # import sys # import subprocess -# +# # #-------------------------------------------- -# +# # 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] ) -# +# # #-------------------------------------------- -# +# # test_fdb=os.path.join(context['temp_directory'],'tmp_0337.fdb') -# +# # cleanup( test_fdb, ) -# +# # db_conn.close() # sql=''' # set echo on; -# +# # show sql dialect; -# +# # set sql dialect 1; -# +# # show sql dialect; -# +# # set sql dialect 3; -# +# # create database 'localhost:%(test_fdb)s' user '%(user_name)s' password '%(user_password)s'; -# +# # show sql dialect; -# +# # drop database; -# +# # show database; -# +# # show sql dialect; -# +# # set sql dialect 1; # ''' % dict(globals(), **locals()) -# +# # f_sql_chk = open( os.path.join(context['temp_directory'],'tmp_0337_ddl.sql'), 'w', buffering = 0) # f_sql_chk.write(sql) # flush_and_close( f_sql_chk ) -# +# # f_sql_log = open( ''.join( (os.path.splitext(f_sql_chk.name)[0], '.log' ) ), 'w', buffering = 0) # subprocess.call( [ context['isql_path'], '-q', '-i', f_sql_chk.name ], stdout = f_sql_log, stderr = subprocess.STDOUT) # flush_and_close( f_sql_log ) -# +# # with open(f_sql_log.name,'r') as f: # for line in f: # if line.split(): # print( line.upper() ) -# +# # cleanup( (test_fdb, f_sql_log.name, f_sql_chk.name) ) -# -# +# +# #--- -#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1) expected_stdout_1 = """ SHOW SQL DIALECT; - CLIENT SQL DIALECT HAS NOT BEEN SET AND NO DATABASE HAS BEEN CONNECTED YET. + Client SQL dialect has not been set and no database has been connected yet. SET SQL DIALECT 1; SHOW SQL DIALECT; - CLIENT SQL DIALECT IS SET TO: 1. NO DATABASE HAS BEEN CONNECTED. + Client SQL dialect is set to: 1. No database has been connected. SET SQL DIALECT 3; CREATE DATABASE 'LOCALHOST:C:\\FBTESTING\\QA\\FBT-REPO\\TMP2\\TMP_0337.FDB' USER 'SYSDBA' PASSWORD 'MASTERKEY'; SHOW SQL DIALECT; - CLIENT SQL DIALECT IS SET TO: 3 AND DATABASE SQL DIALECT IS: 3 + Client SQL dialect is set to: 3 and database SQL dialect is: 3 DROP DATABASE; - + SHOW DATABASE; - COMMAND ERROR: SHOW DATABASE SHOW SQL DIALECT; - CLIENT SQL DIALECT IS SET TO: 3. NO DATABASE HAS BEEN CONNECTED. + Client SQL dialect is set to: 3. No database has been connected. SET SQL DIALECT 1; """ +expected_stderr_1 = """ +Use CONNECT or CREATE DATABASE to specify a database +Use CONNECT or CREATE DATABASE to specify a database +Command error: SHOW DATABASE +""" + +act_1 = isql_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): + act_1.db.drop() + act_1.script = f""" + SET ECHO ON; + SHOW SQL DIALECT; + SET SQL DIALECT 1; + SHOW SQL DIALECT; + SET SQL DIALECT 3; + CREATE DATABASE '{act_1.db.dsn}' USER '{act_1.db.user}' PASSWORD '{act_1.db.password}'; + SHOW SQL DIALECT; + DROP DATABASE; + SHOW DATABASE; + SHOW SQL DIALECT; + SET SQL DIALECT 1; + """ + act_1.expected_stdout = expected_stdout_1 + act_1.expected_stderr = expected_stderr_1 + act_1.execute(do_not_connect=True) + assert act_1.clean_expected_stdout == act_1.clean_stdout + assert act_1.clean_expected_stderr == act_1.clean_stderr + act_1.db.create() + diff --git a/tests/bugs/core_0405_test.py b/tests/bugs/core_0405_test.py index 5ab277b8..53d7cb8c 100644 --- a/tests/bugs/core_0405_test.py +++ b/tests/bugs/core_0405_test.py @@ -2,7 +2,7 @@ # # id: bugs.core_0405 # title: Garbage vs indices/constraints -# decription: +# decription: # Confirmed bug on 3.0.4.32924, got: # DatabaseError: # Error while commiting transaction: @@ -14,14 +14,14 @@ # :: NB :: # No error on Firebird 4.0 (any: SS,SC, CS). # Works OK on: 4.0.0.838 -# +# # tracker_id: CORE-0405 # min_versions: ['3.0.4'] # versions: 3.0.4 # 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.4 # resources: None @@ -34,63 +34,84 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # test_script_1 #--- -# +# # import os # import sys # import fdb -# +# # os.environ["ISC_USER"] = user_name # os.environ["ISC_PASSWORD"] = user_password -# +# # db_conn.close() -# +# # con=fdb.connect( dsn=dsn, no_gc=1 ) # #print( con.firebird_version ) -# +# # con.execute_immediate('recreate table test(x int)') # con.commit() # cur=con.cursor() -# +# # stm='insert into test( x ) values( ? )' # val = [ (2,), (3,), (3,), (2,) ] # cur.executemany( stm, val ) -# +# # cur.execute('select x from test order by x') # for r in cur: # print(r[0]) -# +# # cur.execute('delete from test') -# +# # cur.execute('select count(*) from test') # for r in cur: # print(r[0]) -# +# # con.execute_immediate('create unique index test_x on test(x)') # con.commit() -# -# +# +# # cur.execute("select rdb$index_name from rdb$indices where rdb$relation_name='TEST'") # for r in cur: # print( r[0].rstrip() ) -# +# # con.close() -# -# +# +# #--- -#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1) -expected_stdout_1 = """ - 2 - 2 - 3 - 3 - 0 - TEST_X - """ +act_1 = python_act('db_1', substitutions=substitutions_1) + +expected_stdout_1 = """2 +2 +3 +3 +0 +TEST_X +""" @pytest.mark.version('>=3.0.4') -@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: + con.execute_immediate('recreate table test(x int)') + con.commit() + cur = con.cursor() + + cur.executemany('insert into test( x ) values( ? )', [(2,), (3,), (3,), (2,)]) + + for r in cur.execute('select x from test order by x'): + print(r[0]) + + cur.execute('delete from test') + + for r in cur.execute('select count(*) from test'): + print(r[0]) + + con.execute_immediate('create unique index test_x on test(x)') + con.commit() + + for r in cur.execute("select rdb$index_name from rdb$indices where rdb$relation_name='TEST'"): + print(r[0].rstrip()) + # + output = capsys.readouterr() + assert output.out == expected_stdout_1 diff --git a/tests/bugs/core_0733_test.py b/tests/bugs/core_0733_test.py index bba110f2..969f8a28 100644 --- a/tests/bugs/core_0733_test.py +++ b/tests/bugs/core_0733_test.py @@ -2,7 +2,7 @@ # # id: bugs.core_0733 # title: Compress Data over the Network -# decription: +# decription: # CHANGED 22.12.2019: CODE REDUCTION: REMOVED MEASURES OT TIME. # Results are completely opposite to those which were obtained on snapshots when this test was implenmented (3.0.5.33084, 4.0.0.1347). # Requirement to compress data leads to DEGRADATION of performance when data are stored on local machine, and we have no ability @@ -10,16 +10,16 @@ # After discuss with dimitr it was decided to remove any logging and its analysis. # We only verify matching of RDB$GET_CONTEXT('SYSTEM', 'WIRE_COMPRESSED') and value that was stored in the firebird.conf # for current check. -# +# # ### NOTE ### -# Changed value of parameter WireCompression (in firebird.conf) will be seen by application if it reloads client library. +# Changed value of parameter WireCompression (in firebird.conf) will be seen by application if it reloads client library. # Reconnect is NOT enough for this. For this reason we use subprocess and call ISQL utility to do above mentioned actions # in new execution context. -# +# # See also tests for: # CORE-5536 - checks that field mon$wire_compressed actually exists in MON$ATTACHMENTS table; # CORE-5913 - checks that built-in rdb$get_context('SYSTEM','WIRE_ENCRYPTED') is avaliable; -# +# # Checked on: # 4.0.0.1693 SS: 3.031s. # 4.0.0.1346 SC: 2.890s. @@ -27,8 +27,12 @@ # 3.0.5.33215 SS: 1.452s. # 3.0.5.33084 SC: 1.344s. # 3.0.5.33212 CS: 3.175s. -# -# +# +# [pcisar] 9.11.2021 +# This test was fragile from start, usualy lefts behind resources and requires +# temporary changes to firebird.conf on run-time. It's questionable whether +# wire-compression should be tested at all. +# # tracker_id: CORE-0733 # min_versions: ['3.0.0'] # versions: 3.0 @@ -46,8 +50,8 @@ init_script_1 = """ create domain dm_dump varchar(32700) character set none; recreate table t_log( required_value varchar(5), actual_value varchar(5), elap_ms int ); commit; - set term ^; - create or alter procedure sp_uuid(a_compressable boolean, n_limit int default 1) + set term ^; + create or alter procedure sp_uuid(a_compressable boolean, n_limit int default 1) returns (b dm_dump) as declare g char(16) character set octets; begin @@ -76,7 +80,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # test_script_1 #--- -# +# # import os # import time as tm # import datetime @@ -85,86 +89,86 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # import shutil # import subprocess # import platform -# +# # from fdb import services -# +# # os.environ["ISC_USER"] = user_name # os.environ["ISC_PASSWORD"] = user_password -# +# # DB_NAME = '$(DATABASE_LOCATION)' + 'bugs.core_0733.fdb' -# +# # DB_PATH = '$(DATABASE_LOCATION)' # U_NAME = user_name # U_PSWD = user_password # NUL_DEVICE = 'nul' if platform.system() == 'Windows' else '/dev/null' -# +# # N_ROWS = 1 -# +# # F_SQL_NAME=os.path.join(context['temp_directory'],'tmp_core_0733.sql') -# +# # fb_home = services.connect(host='localhost', user= user_name, password= user_password).get_home_directory() # dts = datetime.datetime.now().strftime("%y%m%d_%H%M%S") # fbconf_bak = fb_home+'firebird_'+dts+'.tmp_0733.bak' # shutil.copy2( fb_home+'firebird.conf', fbconf_bak ) -# +# # 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 prepare_fb_conf( fb_home, a_required_value ): -# +# # f_fbconf=open(fb_home+'firebird.conf','r') # fbconf_content=f_fbconf.readlines() # f_fbconf.close() # for i,s in enumerate( fbconf_content ): # if s.lower().lstrip().startswith( 'wirecompression'.lower() ): # fbconf_content[i] = '# ' + s -# +# # fbconf_content.append('\\n# Temporarily added by fbtest, CORE-0733. Should be removed auto:') # fbconf_content.append("\\n#" + '='*30 ) # fbconf_content.append('\\nWireCompression = %s' % a_required_value ) # fbconf_content.append("\\n#" + '='*30 ) # fbconf_content.append("\\n" ) -# +# # f_fbconf=open(fb_home+'firebird.conf','w') # f_fbconf.writelines( fbconf_content ) # f_fbconf.close() # #------------------------------------------------------------------------------------ -# +# # def prepare_sql_4run( required_compression, db_path, n_rows, sql_file_name ): # global os # global U_NAME # global U_PSWD # global NUL_DEVICE -# +# # sql_dump='tmp_core_0733_compression_%(required_compression)s.dump' % ( locals() ) -# +# # if os.path.isfile( '%(db_path)s%(sql_dump)s' % (locals()) ): # os.remove( '%(db_path)s%(sql_dump)s' % (locals()) ) -# +# # if n_rows is None: # return -# +# # #------------------ -# +# # sql_text=''' # set list on; -# +# # set term ^; # execute block returns(dts timestamp) as # begin @@ -174,10 +178,10 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # end # ^ # set term ;^ -# +# # --out %(db_path)s%(sql_dump)s; # out nul; -# +# # set term ^; # execute block returns(b dm_dump) as # begin @@ -194,7 +198,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # ^ # set term ;^ # out; -# +# # set term ^; # execute block returns(dts timestamp) as # begin @@ -204,97 +208,97 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # end # ^ # set term ;^ -# +# # insert into t_log( required_value, actual_value, elap_ms) # values( # upper( '%(required_compression)s' ) # ,upper( rdb$get_context('SYSTEM','WIRE_COMPRESSED') ) -# ,datediff( millisecond -# from cast(rdb$get_context('USER_SESSION','DTS_BEG') as timestamp) -# to cast(rdb$get_context('USER_SESSION','DTS_END') as timestamp) -# ) +# ,datediff( millisecond +# from cast(rdb$get_context('USER_SESSION','DTS_BEG') as timestamp) +# to cast(rdb$get_context('USER_SESSION','DTS_END') as timestamp) +# ) # ) # returning required_value, actual_value, elap_ms # ; # commit; # ''' % dict(globals(), **locals()) # # ( locals() ) -# +# # f_sql=open( sql_file_name, 'w') # f_sql.write( sql_text ) # f_sql.close() -# +# # #------------------------- -# +# # # Call for removing dump from disk: # prepare_sql_4run( 'false', DB_PATH, None, None ) # prepare_sql_4run( 'true', DB_PATH, None, None ) -# -# +# +# # REQUIRED_WIRE_COMPRESSION = 'false' # # ------------------------------------------------------ ########### # # Generate SQL script for running when WireCompression = |||FALSE||| # # ------------------------------------------------------ ########### # prepare_sql_4run( REQUIRED_WIRE_COMPRESSION, DB_PATH, N_ROWS, F_SQL_NAME ) -# +# # # ------------------------------------------------------ ########### # # Update content of firebird.conf with WireCompression = |||FALSE||| # # ------------------------------------------------------ ########### # prepare_fb_conf( fb_home, REQUIRED_WIRE_COMPRESSION) -# -# +# +# # # -------------------------------------------------------------------------------------- # # Launch ISQL in separate context of execution with job to obtain data and log duration # # -------------------------------------------------------------------------------------- -# +# # fn_log = open(os.devnull, 'w') # #fn_log = open( os.path.join(context['temp_directory'],'tmp_0733_with_compression.log'), 'w') # f_isql_obtain_data_err = open( os.path.join(context['temp_directory'],'tmp_0733_obtain_data.err'), 'w') -# +# # subprocess.call( [ context['isql_path'], dsn, "-i", F_SQL_NAME ], # stdout = fn_log, # stderr = f_isql_obtain_data_err # ) # fn_log.close() # f_isql_obtain_data_err.close() -# +# # # Call for removing dump from disk: # #prepare_sql_4run( False, DB_PATH, None, None ) # #prepare_sql_4run( True, DB_PATH, None, None ) -# -# +# +# # # Update content of firebird.conf with WireCompression = true # ############################################################## -# +# # REQUIRED_WIRE_COMPRESSION = 'true' # # ------------------------------------------------------ ########### # # Generate SQL script for running when WireCompression = ||| TRUE||| # # ------------------------------------------------------ ########### # prepare_sql_4run( REQUIRED_WIRE_COMPRESSION, DB_PATH, N_ROWS, F_SQL_NAME ) -# +# # # ------------------------------------------------------ ########### # # Update content of firebird.conf with WireCompression = ||| TRUE||| # # ------------------------------------------------------ ########### # prepare_fb_conf( fb_home, REQUIRED_WIRE_COMPRESSION) -# -# fn_log = open(os.devnull, 'w') +# +# fn_log = open(os.devnull, 'w') # #fn_log = open( os.path.join(context['temp_directory'],'tmp_0733_without_compress.log'), 'w') # f_isql_obtain_data_err = open( os.path.join(context['temp_directory'],'tmp_0733_obtain_data.err'), 'a') -# +# # subprocess.call( [ context['isql_path'], dsn, "-i", F_SQL_NAME ], # stdout = fn_log, # stderr = f_isql_obtain_data_err # ) # fn_log.close() # flush_and_close( f_isql_obtain_data_err ) -# +# # # Call for removing dump from disk: # #prepare_sql_4run( REQUIRED_WIRE_COMPRESSION, DB_PATH, None, None ) -# +# # # RESTORE original config: # ########################## # shutil.copy2( fbconf_bak , fb_home+'firebird.conf') -# +# # sql=''' # -- select * from t_log; # -- REQUIRED_VALUE ACTUAL_VALUE ELAP_MS @@ -304,15 +308,15 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # set list on; # select # result_of_req_compare_to_actual -# --,iif( slowest_with_compression < fastest_without_compression, -# -- 'EXPECTED: compression was FASTER.', +# --,iif( slowest_with_compression < fastest_without_compression, +# -- 'EXPECTED: compression was FASTER.', # -- 'POOR. slowest_with_compression=' || slowest_with_compression || ', fastest_without_compression=' || fastest_without_compression # -- ) as result_of_compression_benchmark # from ( -# select +# select # min( iif( upper(required_value) is distinct from upper(actual_value) # ,coalesce(required_value,'') || coalesce(actual_value,'') -# ,'EXPECTED: actual values were equal to required.' +# ,'EXPECTED: actual values were equal to required.' # ) # ) as result_of_req_compare_to_actual # ,min( iif( upper(required_value) = upper('false'), elap_ms, null ) ) fastest_without_compression @@ -322,14 +326,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # ; # set list off; # --select * from t_log; -# +# # ''' # runProgram('isql', [ dsn ], sql) -# -# +# +# # # Additional check: STDERR for ISQL must be EMPTY. # ################################################## -# +# # f_list=(f_isql_obtain_data_err,) # for i in range(len(f_list)): # f_name=f_list[i].name @@ -337,12 +341,12 @@ 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) -# +# # os.remove(f_isql_obtain_data_err.name) # os.remove(fbconf_bak) # os.remove(F_SQL_NAME) -# -# +# +# #--- #act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1) diff --git a/tests/bugs/core_0790_test.py b/tests/bugs/core_0790_test.py index 434ce204..9d9c69f8 100644 --- a/tests/bugs/core_0790_test.py +++ b/tests/bugs/core_0790_test.py @@ -2,7 +2,7 @@ # # id: bugs.core_0790 # title: Alter view -# decription: +# decription: # tracker_id: CORE-790 # min_versions: ['2.5.0'] # versions: 2.5.0 @@ -46,7 +46,7 @@ show view v_users_name; act_1 = isql_act('db_1', test_script_1, substitutions=substitutions_1) -expected_stdout_1 = """Database: localhost:C: btest2 mpugs.core_0790.fdb, User: SYSDBA +expected_stdout_1 = """Database: localhost:C:/fbtest2/tmp/bugs.core_0790.fdb, User: SYSDBA SQL> CON> SQL> SQL> ID INTEGER Nullable NAME VARCHAR(20) Nullable PASSWD VARCHAR(20) Nullable @@ -65,7 +65,8 @@ View Source: ==== ====== select name from v_users -SQL> SQL> SQL> SQL>""" +SQL> SQL> SQL> SQL> +""" @pytest.mark.version('>=2.5.0') def test_1(act_1: Action): diff --git a/tests/bugs/core_0800_test.py b/tests/bugs/core_0800_test.py index e0e01cf3..256bb338 100644 --- a/tests/bugs/core_0800_test.py +++ b/tests/bugs/core_0800_test.py @@ -2,16 +2,16 @@ # # id: bugs.core_0800 # title: Easy metadata extract improvements -# decription: +# decription: # Domain DDL: move its CHECK clause from 'create' to 'alter' statement. -# +# # tracker_id: CORE-0800 # 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 @@ -37,10 +37,10 @@ init_script_1 = """ create collation name_coll for utf8 from unicode no pad case insensitive accent insensitive; commit; - create domain dm_test varchar(20) - character set utf8 - default 'foo' - not null + create domain dm_test varchar(20) + character set utf8 + default 'foo' + not null check (value in ('foo', 'rio', 'bar')) collate name_coll ; @@ -53,46 +53,49 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1) #--- # import os # import subprocess -# +# # db_conn.close() -# +# # os.environ["ISC_USER"] = user_name # os.environ["ISC_PASSWORD"] = user_password # db_file="$(DATABASE_LOCATION)bugs.core_0800.fdb" -# +# # f_extract_meta = open( os.path.join(context['temp_directory'],'tmp_meta_0800_init.sql'), 'w') # subprocess.call( [context['isql_path'], dsn, "-x", "-ch", "utf8"], # stdout = f_extract_meta, # stderr = subprocess.STDOUT # ) # f_extract_meta.close() -# +# # with open( f_extract_meta.name, 'r') as f: # for line in f: # if 'ALTER DOMAIN' in line.upper(): # print( line ) -# +# # ############################### # # Cleanup. -# +# # f_list=[] # f_list.append(f_extract_meta) -# +# # for i in range(len(f_list)): # if os.path.isfile(f_list[i].name): # os.remove(f_list[i].name) -# -# +# +# #--- -#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1) + +act_1 = python_act('db_1', substitutions=substitutions_1) expected_stdout_1 = """ ALTER DOMAIN DM_TEST ADD CONSTRAINT """ @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 + act_1.extract_meta() + expected = ''.join([x for x in act_1.clean_stdout.splitlines() if 'ALTER DOMAIN' in x.upper()]) + assert act_1.clean_expected_stdout == expected diff --git a/tests/bugs/core_0857_test.py b/tests/bugs/core_0857_test.py index 4d32bc04..37499a47 100644 --- a/tests/bugs/core_0857_test.py +++ b/tests/bugs/core_0857_test.py @@ -2,7 +2,7 @@ # # id: bugs.core_0857 # title: Containing not working correctly -# decription: +# decription: # Could not find build 2.0 RC3. # Checked on: # 4.0.0.1713 SS: 1.625s. @@ -10,15 +10,15 @@ # 3.0.5.33218 SS: 1.000s. # 3.0.5.33084 SC: 0.890s. # 2.5.9.27149 SC: 0.266s. -# +# # 02-mar-2021. Re-implemented in ordeer to have ability to run this test on Linux. # We run 'init_script' using charset = utf8 but then run separate ISQL-process # with request to establish connection using charset = win1252. -# +# # Checked on: # * Windows: 4.0.0.2377, 3.0.8.33420, 2.5.9.27152 # * Linux: 4.0.0.2377, 3.0.8.33415 -# +# # tracker_id: CORE-857 # min_versions: ['2.5.0'] # versions: 2.5 @@ -55,7 +55,7 @@ db_1 = db_factory(charset='WIN1252', sql_dialect=3, init=init_script_1) # test_script_1 #--- -# +# # sql_cmd=''' # set names win1252; # connect '%(dsn)s' user '%(user_name)s' password '%(user_password)s'; @@ -64,7 +64,7 @@ db_1 = db_factory(charset='WIN1252', sql_dialect=3, init=init_script_1) # from mon$attachments a # join rdb$character_sets c on a.mon$character_set_id = c.rdb$character_set_id # where a.mon$attachment_id = current_connection; -# +# # select t.id as "test_1 result:" from rdb$database r left join test t on t.f01 not containing 'P1' and t.f01 like 'IHF|gro_|850_C|P1'; # select t.id as "test_2 result:" from rdb$database r left join test t on t.f01 containing 'P1' and t.f01 like 'IHF|gro_|850_C|P1'; # select t.id as "ci_ai result:" from rdb$database r left join test t on lower(t.f02) = upper(t.f02); @@ -72,8 +72,8 @@ db_1 = db_factory(charset='WIN1252', sql_dialect=3, init=init_script_1) # select * from v_test; # ''' % dict(globals(), **locals()) # runProgram( 'isql', [ '-q' ], sql_cmd) -# -# +# +# #--- #act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1) @@ -86,9 +86,27 @@ expected_stdout_1 = """ octet_length diff: 1 """ +test_script_1 = """ + set list on; + select c.rdb$character_set_name as connection_cset + from mon$attachments a + join rdb$character_sets c on a.mon$character_set_id = c.rdb$character_set_id + where a.mon$attachment_id = current_connection; + + select t.id as "test_1 result:" from rdb$database r left join test t on t.f01 not containing 'P1' and t.f01 like 'IHF|gro_|850_C|P1'; + select t.id as "test_2 result:" from rdb$database r left join test t on t.f01 containing 'P1' and t.f01 like 'IHF|gro_|850_C|P1'; + select t.id as "ci_ai result:" from rdb$database r left join test t on lower(t.f02) = upper(t.f02); + select t.id as "between result:" from rdb$database r left join test t on lower(t.f01) between lower(t.f02) and upper(t.f02); + select * from v_test; +""" + +act_1 = isql_act('db_1', test_script_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): + act_1.charset = 'WIN1252' + act_1.expected_stdout = expected_stdout_1 + act_1.execute() + assert act_1.clean_expected_stdout == act_1.clean_stdout diff --git a/tests/bugs/core_0929_test.py b/tests/bugs/core_0929_test.py index c284fa7b..86f48106 100644 --- a/tests/bugs/core_0929_test.py +++ b/tests/bugs/core_0929_test.py @@ -2,14 +2,14 @@ # # id: bugs.core_0929 # title: Bug in DSQL parameter -# decription: +# decription: # tracker_id: CORE-929 # min_versions: [] # versions: 2.1 # qmid: bugs.core_929 import pytest -from firebird.qa import db_factory, isql_act, Action +from firebird.qa import db_factory, python_act, Action # version: 2.1 # resources: None @@ -37,14 +37,18 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # except Exception,e: # print ('Test FAILED') # print (e) -# +# #--- -#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') -@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() + try: + c.prepare('SELECT * FROM TEST WHERE MYDATE + CAST(? AS INTEGER) >= ?') + except: + pytest.fail("Test FAILED") diff --git a/tests/bugs/core_0959_test.py b/tests/bugs/core_0959_test.py index 138746d6..73ebb17e 100644 --- a/tests/bugs/core_0959_test.py +++ b/tests/bugs/core_0959_test.py @@ -2,9 +2,9 @@ # # id: bugs.core_0959 # title: GSTAT does not work using the localhost connection string -# decription: +# decription: # Refactored 17.11.2017. Covers ticket CORE-5629. -# +# # For 3.0+ we check in log of GSTAT presense of following lines: # * with timestamp of GSTAT start # * with DB name @@ -13,30 +13,41 @@ # * with count of data pages and average fill for table 'TEST' # * with number of index root page, depath of index and number of buckets and nodes for index 'TEST_S' # * with timestamp of GSTAT finish. -# If line from log matches to any of pattenrs then we do output if this line for checking in 'expected_stdout' section. +# If line from log matches to any of patterns then we do output if this line for checking in 'expected_stdout' section. # Otherwise line is ignored. -# +# # Check is done using regexp searches -- see definition of patterns hdr_dbname_ptn, hdr_dbattr_ptn, table_ppip_ptn etc. -# +# # For 2.5.x check was changed only by added line with with timestamp of GSTAT start in 'expected_stdout' section. -# +# # Checked on: # FB25SC, build 2.5.8.27078: OK, 0.297s. # FB30SS, build 3.0.3.32837: OK, 2.344s. # FB40SS, build 4.0.0.800: OK, 2.437s. -# +# +# [pcisar] 9.11.2021 +# This test is wrong as it uses service manager. +# It should use gstat directly with pseudo-remote path (i.e. localhost:filename) +# # tracker_id: CORE-959 # min_versions: ['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 +import re # version: 3.0 # resources: None -substitutions_1 = [('Database ".*', 'Database'), ('Gstat execution time .*', 'Gstat execution time'), ('Attributes .*', 'Attributes'), ('Primary pointer page: \\d+, Index root page: \\d+\\s*', 'Primary pointer page, Index root page'), ('Data pages: \\d+, average fill: \\d+[percent_sign]', 'Data pages, average fill'), ('Root page: \\d+, depth: \\d+, leaf buckets: \\d+, nodes: \\d+\\s*', 'Root page, depth, leaf buckets, nodes'), ('Gstat completion time .*', 'Gstat completion time')] +substitutions_1 = [('Database ".*', 'Database'), + ('Gstat execution time .*', 'Gstat execution time'), + ('Attributes .*', 'Attributes'), + ('Primary pointer page: \\d+, Index root page: \\d+\\s*', 'Primary pointer page, Index root page'), + ('Data pages: \\d+, average fill: \\d+[percent_sign]', 'Data pages, average fill'), + ('Root page: \\d+, depth: \\d+, leaf buckets: \\d+, nodes: \\d+\\s*', 'Root page, depth, leaf buckets, nodes'), + ('Gstat completion time .*', 'Gstat completion time')] init_script_1 = """ create sequence g; @@ -50,25 +61,25 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # test_script_1 #--- -# +# # import os # import sys # import subprocess # import time # import re -# +# # os.environ["ISC_USER"] = user_name # os.environ["ISC_PASSWORD"] = user_password -# +# # hdr_dbname_ptn=re.compile('Database\\s+"', re.IGNORECASE) # hdr_dbattr_ptn=re.compile('Attributes\\s+\\.*', re.IGNORECASE) # table_ppip_ptn=re.compile('Primary\\s+pointer\\s+page:\\s+\\d+,\\s+Index root page:\\s+\\d+\\s*', re.IGNORECASE) # table_dpaf_ptn=re.compile('Data\\s+pages:\\s+\\d+,\\s+average\\s+fill:\\s+\\d+%\\s*', re.IGNORECASE) # index_root_ptn=re.compile('Root\\s+page:\\s+\\d+,\\s+depth:\\s+\\d+,\\s+leaf\\s+buckets:\\s+\\d+,\\s+nodes:\\s+\\d+\\s*', re.IGNORECASE) -# +# # gstat_init_ptn=re.compile('Gstat\\s+execution\\s+time\\s+', re.IGNORECASE) # gstat_fini_ptn=re.compile('Gstat\\s+completion\\s+time\\s+', re.IGNORECASE) -# +# # watched_ptn_list=( # hdr_dbname_ptn # ,hdr_dbattr_ptn @@ -80,24 +91,24 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # ) # db_name=db_conn.database_name # 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() -# +# # #-------------------------------------------- -# +# # f_dbstat_log = open( os.path.join(context['temp_directory'],'tmp_local_host_0959.log'), 'w') # f_dbstat_err = open( os.path.join(context['temp_directory'],'tmp_local_host_0959.err'), 'w') # context['isql_path'] @@ -112,39 +123,40 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # stdout=f_dbstat_log, # stderr=f_dbstat_err # ) -# +# # flush_and_close( f_dbstat_log ) # flush_and_close( f_dbstat_err ) -# +# # with open( f_dbstat_log.name,'r') as f: # for line in f: # if line.split(): # for p in watched_ptn_list: # if p.search( line ): # print( ' '.join(line.replace('%','[percent_sign]').split()) ) -# +# # with open( f_dbstat_err.name,'r') as f: # for line in f: # if line.split(): # print('UNEXPECTED STDERR in '+f_dbstat_err.name+': '+line) -# -# +# +# # ##################### # # Cleanup. # time.sleep(1) -# -# f_list=( +# +# f_list=( # f_dbstat_log # ,f_dbstat_err # ) -# +# # for i in range(len(f_list)): # if os.path.isfile(f_list[i].name): # os.remove(f_list[i].name) -# -# +# +# #--- -#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 "C:\\MIX\\FIREBIRD\\QA\\FBT-REPO\\TMP\\BUGS.CORE_0959.FDB" @@ -157,8 +169,31 @@ expected_stdout_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): + hdr_dbname_ptn = re.compile('Database\\s+"', re.IGNORECASE) + hdr_dbattr_ptn = re.compile('Attributes\\s+\\.*', re.IGNORECASE) + table_ppip_ptn = re.compile('Primary\\s+pointer\\s+page:\\s+\\d+,\\s+Index root page:\\s+\\d+\\s*', re.IGNORECASE) + table_dpaf_ptn = re.compile('Data\\s+pages:\\s+\\d+,\\s+average\\s+fill:\\s+\\d+%\\s*', re.IGNORECASE) + index_root_ptn = re.compile('Root\\s+page:\\s+\\d+,\\s+depth:\\s+\\d+,\\s+leaf\\s+buckets:\\s+\\d+,\\s+nodes:\\s+\\d+\\s*', re.IGNORECASE) + # + gstat_init_ptn = re.compile('Gstat\\s+execution\\s+time\\s+', re.IGNORECASE) + gstat_fini_ptn = re.compile('Gstat\\s+completion\\s+time\\s+', re.IGNORECASE) + # + watched_ptn_list = [hdr_dbname_ptn, hdr_dbattr_ptn, table_ppip_ptn, table_dpaf_ptn, + index_root_ptn, gstat_init_ptn, gstat_fini_ptn] + # + act_1.expected_stdout = expected_stdout_1 + act_1.gstat(switches=['-d', '-i', '-r']) + # + matched = [] + for line in act_1.stdout.splitlines(): + for p in watched_ptn_list: + if p.search(line): + matched.append(' '.join(line.replace('%','[percent_sign]').split())) + # + actual = '\n'.join(matched) + actual = act_1.string_strip(actual, act_1.substitutions) + assert 'localhost' in act_1.db.dsn + assert act_1.clean_expected_stdout == actual diff --git a/tests/bugs/core_0967_test.py b/tests/bugs/core_0967_test.py index 8dc764ea..4059ce76 100644 --- a/tests/bugs/core_0967_test.py +++ b/tests/bugs/core_0967_test.py @@ -2,14 +2,15 @@ # # id: bugs.core_0967 # title: SQL with incorrect characters (outside the ASCII range) may be processed wrongly -# decription: +# decription: # tracker_id: CORE-967 # min_versions: [] # versions: 2.1 # qmid: bugs.core_967 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.1 # resources: None @@ -36,14 +37,18 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # c.execute('select * from t') # printData(c) #--- -#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1) -expected_stdout_1 = """'Error while preparing SQL statement:/n- SQLCODE: -104/n- Dynamic SQL Error/n- SQL error code = -104/n- Token unknown - line 1, column 17/n- /xee' -""" +act_1 = python_act('db_1', substitutions=substitutions_1) + +#expected_stdout_1 = """'Error while preparing SQL statement:/n- SQLCODE: -104/n- Dynamic SQL Error/n- SQL error code = -104/n- Token unknown - line 1, column 17/n- /xee' +#""" @pytest.mark.version('>=2.1') -@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() + with pytest.raises(DatabaseError, match="Dynamic SQL Error\n-SQL error code = -104\n-Token unknown - line 1, column 17\n.*") as excinfo: + c.execute('update t set i=1'+chr(238)+' where 1=0') + diff --git a/tests/bugs/core_0986_test.py b/tests/bugs/core_0986_test.py index fda843db..76dd1b1a 100644 --- a/tests/bugs/core_0986_test.py +++ b/tests/bugs/core_0986_test.py @@ -2,7 +2,7 @@ # # id: bugs.core_0986 # title: Non-ASCII quoted identifiers are not converted to metadata (UNICODE_FSS) charset -# decription: +# decription: # Test prepares file that will serve as input SQL script and will have CYRYLLIC names for all # database objects: collations, domains, exceptions, tables, views etc. # File has name = 'tmp_non_ascii_ddl_0986.sql' and is encoded to windows-1251 codepage. @@ -14,47 +14,48 @@ # 1.2) STDERR with single exception, it depends on major FB version: # * for FB 3.x: SQLSTATE = 22000 / malformed string; # * for FB 4.x: SQLSTATE = 22018 / Cannot transliterate ... -# +# # 2. Attempt to apply the same script but now _WITH_ specification of connect charset: -ch win1251. # This attempt should finish SUCCESSFULLY, and we will verify it by checking its: # 2.1) STDOUT - it should contain phrase "Metadata created OK." # 2.2) STDERR - it should be EMPTY. -# +# # Confirmed on 2.0.7: one might to run ISQL without specifying '-ch XXXX' switch and give it -# script which -# 1) was encoded in NON unicode character set (e.g. win1251 - as is used in this test) and +# script which +# 1) was encoded in NON unicode character set (e.g. win1251 - as is used in this test) and # 2) did create DB objects with non-ascii names. -# +# # Checked on: # 4.0.0.1635 SS: 3.217s. # 4.0.0.1633 CS: 3.619s. # 3.0.5.33180 SS: 2.548s. # 3.0.5.33178 CS: 3.153s. -# +# # 17-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 = WIN1251 and perform needed DML. # Result will be redirected to .log which will be opened via codecs.open(...encoding='cp1251'). # Its content will be converted to UTF8 for further parsing. -# +# # Checked on: # * Windows: 4.0.0.2387, 3.0.8.33426 # * Linux: 4.0.0.2387, 3.0.8.33426 -# -# +# +# # tracker_id: CORE-0986 # 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, temp_file +from pathlib import Path # version: 3.0 # resources: None -substitutions_1 = [] +substitutions_1 = [('in file .*', 'in file XXX')] init_script_1 = """""" @@ -65,30 +66,30 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # import os # import time # import subprocess -# +# # # 28.10.2019. This is needed in Python 2.7 for converting string in UTF8 to cp1251 # import codecs -# +# # 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 )): @@ -99,54 +100,54 @@ 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 ) -# +# # #-------------------------------------------- -# -# +# +# # # Obtain engine version: # cur1 = db_conn.cursor() # cur1.execute("select rdb$get_context('SYSTEM','ENGINE_VERSION') as engine_version from rdb$database") # for row in cur1: # engine = row[0] -# +# # db_conn.close() -# +# # non_ascii_ddl=''' # set bail on; -# +# # -- set names win1251; # connect '%(dsn)s' user '%(user_name)s' password '%(user_password)s'; -# +# # set echo on; -# +# # create collation "Циферки" for utf8 from unicode case insensitive 'NUMERIC-SORT=1'; # create collation "Испания" for iso8859_1 from es_es_ci_ai 'SPECIALS-FIRST=1';; # commit; -# +# # create domain "ИД'шники" int; # create domain "Группы" varchar(30) check( value in ('Электрика', 'Ходовая', 'Арматурка', 'Кузовщина') ); -# create domain "Артикулы" varchar(12) character set utf8 check( value = upper(value) ) +# create domain "Артикулы" varchar(12) character set utf8 check( value = upper(value) ) # collate "Циферки" -- enabled since core-5220 was fixed (30.04.2016) # ; -# create domain "Комрады" varchar(40) character set iso8859_1 +# create domain "Комрады" varchar(40) character set iso8859_1 # collate "Испания" -- enabled since core-5220 was fixed (30.04.2016) # ; # create domain "Кол-во" numeric(12,3) not null; -# +# # create sequence generilka; # create sequence "Генерилка"; -# +# # create role "манагер"; # create role "начсклд"; -# +# # -- TEMPLY COMMENTED UNTIL CORE-5209 IS OPEN: # -- ISQL -X ignores connection charset for text of EXCEPTION message (restoring it in initial charset when exception was created) # recreate exception "Невзлет" 'Запись обломалась, ваши не пляшут. Но не стесняйтесь и обязательно заходите еще, мы всегда рады видеть вас. До скорой встречи, товарищ!'; # commit; -# +# # ------------------------------------------------- # recreate table "склад" ( # "ИД'шник" "ИД'шники" @@ -158,25 +159,25 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # ,constraint "ФК-на-родока" foreign key("ИД'родителя") references "склад" ("ИД'шник") using index "склад_ФК" # ,constraint "остаток >=0" check ("сколько там" >= 0) # ); -# +# # recreate view "Электрика"("ид изделия", "Название", "Запас") as -# select -# "ИД'шник" +# select +# "ИД'шник" # ,"Номенклатура" # ,"сколько там" # from "склад" # where "Откудова" = 'Электрика' # ; -# +# # set term ^; # create or alter trigger "склад би" for "склад" active before insert as # begin # --new."ИД'шник" = coalesce( new."ИД'шник", gen_id(generilka, 1) ); -# -- not avail up to 2.5.6: +# -- not avail up to 2.5.6: # new."ИД'шник" = coalesce( new."ИД'шник", gen_id("Генерилка", 1) ); # end # ^ -# +# # create or alter procedure "Доб на склад"( # "Откудова" varchar(30) # ,"Номенклатура" varchar(30) @@ -189,24 +190,24 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # insert into "склад"( # "Откудова" # ,"Номенклатура" -# ,"ИД'родителя" +# ,"ИД'родителя" # ,"сколько там" # ) values ( # :"Откудова" # ,:"Номенклатура" -# ,:"ИД'родителя" +# ,:"ИД'родителя" # ,:"сколько там" # ); -# +# # end # ^ # create or alter procedure "Удалить" as # begin # /* # Антон Павлович Чехов. Каштанка -# +# # 1. Дурное поведение -# +# # Молодая рыжая собака - помесь такса с дворняжкой - очень похожая мордой # на лисицу, бегала взад и вперед по тротуару и беспокойно оглядывалась по # сторонам. Изредка она останавливалась и, плача, приподнимая то одну озябшую @@ -216,38 +217,38 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # end # ^ # set term ;^ -# +# # grant select on "склад" to "манагер"; # grant select, insert, update, delete on "склад" to "начсклд"; # -- no avail in 2.0: grant execute procedure "Доб на склад" to "начсклд"; -# -# +# +# # comment on sequence "Генерилка" is 'Генератор простых идей'; # comment on table "склад" is 'Это всё, что мы сейчас имеем в наличии'; # comment on view "Электрика" is 'Не суй пальцы в розетку, будет бо-бо!'; # comment on procedure "Доб на склад" is 'Процедурка добавления изделия на склад'; # comment on parameter "Доб на склад"."Откудова" is 'Группа изделия, которое собираемся добавить'; -# +# # comment on parameter "Доб на склад"."ИД'родителя" is ' # Федор Михайлович Достоевский -# +# # Преступление и наказание -# +# # Роман в шести частях с эпилогом -# -# +# +# # Часть первая -# +# # I -# В начале июля, в чрезвычайно жаркое время, под вечер, один молодой человек вышел из своей каморки, которую нанимал от жильцов в С -- м переулке, на улицу и медленно, как бы в нерешимости, отправился к К -- ну мосту. -# Он благополучно избегнул встречи с своею хозяйкой на лестнице. Каморка его приходилась под самою кровлей высокого пятиэтажного дома и походила более на шкаф, чем на квартиру. Квартирная же хозяйка его, у которой он нанимал эту каморку с обедом и прислугой, помещалась одною лестницей ниже, в отдельной квартире, и каждый раз, при выходе на улицу, ему непременно надо было проходить мимо хозяйкиной кухни, почти всегда настежь отворенной на лестницу. И каждый раз молодой человек, проходя мимо, чувствовал какое-то болезненное и трусливое ощущение, которого стыдился и от которого морщился. Он был должен кругом хозяйке и боялся с нею встретиться. -# Не то чтоб он был так труслив и забит, совсем даже напротив; но с некоторого времени он был в раздражительном и напряженном состоянии, похожем на ипохондрию. Он до того углубился в себя и уединился от всех, что боялся даже всякой встречи, не только встречи с хозяйкой. Он был задавлен бедностью; но даже стесненное положение перестало в последнее время тяготить его. Насущными делами своими он совсем перестал и не хотел заниматься. Никакой хозяйки, в сущности, он не боялся, что бы та ни замышляла против него. Но останавливаться на лестнице, слушать всякий вздор про всю эту обыденную дребедень, до которой ему нет никакого дела, все эти приставания о платеже, угрозы, жалобы, и при этом самому изворачиваться, извиняться, лгать, -- нет уж, лучше проскользнуть как-нибудь кошкой по лестнице и улизнуть, чтобы никто не видал. -# Впрочем, на этот раз страх встречи с своею кредиторшей даже его самого поразил по выходе на улицу. -# "На какое дело хочу покуситься и в то же время каких пустяков боюсь! -- подумал он с странною улыбкой. -- Гм... да... всё в руках человека, и всё-то он мимо носу проносит, единственно от одной трусости... это уж аксиома... Любопытно, чего люди больше всего боятся? Нового шага, нового собственного слова они всего больше боятся... А впрочем, я слишком много болтаю. Оттого и ничего не делаю, что болтаю. Пожалуй, впрочем, и так: оттого болтаю, что ничего не делаю. Это я в этот последний месяц выучился болтать, лежа по целым суткам в углу и думая... о царе Горохе. Ну зачем я теперь иду? Разве я способен на это? Разве это серьезно? Совсем не серьезно. Так, ради фантазии сам себя тешу; игрушки! Да, пожалуй что и игрушки!" -# На улице жара стояла страшная, к тому же духота, толкотня, всюду известка, леса, кирпич, пыль и та особенная летняя вонь, столь известная каждому петербуржцу, не имеющему возможности нанять дачу, -- всё это разом неприятно потрясло и без того уже расстроенные нервы юноши. Нестерпимая же вонь из распивочных, которых в этой части города особенное множество, и пьяные, поминутно попадавшиеся, несмотря на буднее время, довершили отвратительный и грустный колорит картины. Чувство глубочайшего омерзения мелькнуло на миг в тонких чертах молодого человека. Кстати, он был замечательно хорош собою, с прекрасными темными глазами, темно-рус, ростом выше среднего, тонок и строен. Но скоро он впал как бы в глубокую задумчивость, даже, вернее сказать, как бы в какое-то забытье, и пошел, уже не замечая окружающего, да и не желая его замечать. Изредка только бормотал он что-то про себя, от своей привычки к монологам, в которой он сейчас сам себе признался. В эту же минуту он и сам сознавал, что мысли его порою мешаются и что он очень слаб: второй день как уж он почти совсем ничего не ел. -# Он был до того худо одет, что иной, даже и привычный человек, посовестился бы днем выходить в таких лохмотьях на улицу. Впрочем, квартал был таков, что костюмом здесь было трудно кого-нибудь удивить. Близость Сенной, обилие известных заведений и, по преимуществу, цеховое и ремесленное население, скученное в этих серединных петербургских улицах и переулках, пестрили иногда общую панораму такими субъектами, что странно было бы и удивляться при встрече с иною фигурой. Но столько злобного презрения уже накопилось в душе молодого человека, что, несмотря на всю свою, иногда очень молодую, щекотливость, он менее всего совестился своих лохмотьев на улице. Другое дело при встрече с иными знакомыми или с прежними товарищами, с которыми вообще он не любил встречаться... А между тем, когда один пьяный, которого неизвестно почему и куда провозили в это время по улице в огромной телеге, запряженной огромною ломовою лошадью, крикнул ему вдруг, проезжая: "Эй ты, немецкий шляпник!" -- и заорал во всё горло, указывая на него рукой, -- молодой человек вдруг остановился и судорожно схватился за свою шляпу. Шляпа эта была высокая, круглая, циммермановская, но вся уже изношенная, совсем рыжая, вся в дырах и пятнах, без полей и самым безобразнейшим углом заломившаяся на сторону. Но не стыд, а совсем другое чувство, похожее даже на испуг, охватило его. -# "Я так и знал! -- бормотал он в смущении, -- я так и думал! Это уж всего сквернее! Вот эдакая какая-нибудь глупость, какая-нибудь пошлейшая мелочь, весь замысел может испортить! Да, слишком приметная шляпа... Смешная, потому и приметная... К моим лохмотьям непременно нужна фуражка, хотя бы старый блин какой-нибудь, а не этот урод. Никто таких не носит, за версту заметят, запомнят... главное, потом запомнят, ан и улика. Тут нужно быть как можно неприметнее... Мелочи, мелочи главное!.. Вот эти-то мелочи и губят всегда и всё..." -# +# В начале июля, в чрезвычайно жаркое время, под вечер, один молодой человек вышел из своей каморки, которую нанимал от жильцов в С -- м переулке, на улицу и медленно, как бы в нерешимости, отправился к К -- ну мосту. +# Он благополучно избегнул встречи с своею хозяйкой на лестнице. Каморка его приходилась под самою кровлей высокого пятиэтажного дома и походила более на шкаф, чем на квартиру. Квартирная же хозяйка его, у которой он нанимал эту каморку с обедом и прислугой, помещалась одною лестницей ниже, в отдельной квартире, и каждый раз, при выходе на улицу, ему непременно надо было проходить мимо хозяйкиной кухни, почти всегда настежь отворенной на лестницу. И каждый раз молодой человек, проходя мимо, чувствовал какое-то болезненное и трусливое ощущение, которого стыдился и от которого морщился. Он был должен кругом хозяйке и боялся с нею встретиться. +# Не то чтоб он был так труслив и забит, совсем даже напротив; но с некоторого времени он был в раздражительном и напряженном состоянии, похожем на ипохондрию. Он до того углубился в себя и уединился от всех, что боялся даже всякой встречи, не только встречи с хозяйкой. Он был задавлен бедностью; но даже стесненное положение перестало в последнее время тяготить его. Насущными делами своими он совсем перестал и не хотел заниматься. Никакой хозяйки, в сущности, он не боялся, что бы та ни замышляла против него. Но останавливаться на лестнице, слушать всякий вздор про всю эту обыденную дребедень, до которой ему нет никакого дела, все эти приставания о платеже, угрозы, жалобы, и при этом самому изворачиваться, извиняться, лгать, -- нет уж, лучше проскользнуть как-нибудь кошкой по лестнице и улизнуть, чтобы никто не видал. +# Впрочем, на этот раз страх встречи с своею кредиторшей даже его самого поразил по выходе на улицу. +# "На какое дело хочу покуситься и в то же время каких пустяков боюсь! -- подумал он с странною улыбкой. -- Гм... да... всё в руках человека, и всё-то он мимо носу проносит, единственно от одной трусости... это уж аксиома... Любопытно, чего люди больше всего боятся? Нового шага, нового собственного слова они всего больше боятся... А впрочем, я слишком много болтаю. Оттого и ничего не делаю, что болтаю. Пожалуй, впрочем, и так: оттого болтаю, что ничего не делаю. Это я в этот последний месяц выучился болтать, лежа по целым суткам в углу и думая... о царе Горохе. Ну зачем я теперь иду? Разве я способен на это? Разве это серьезно? Совсем не серьезно. Так, ради фантазии сам себя тешу; игрушки! Да, пожалуй что и игрушки!" +# На улице жара стояла страшная, к тому же духота, толкотня, всюду известка, леса, кирпич, пыль и та особенная летняя вонь, столь известная каждому петербуржцу, не имеющему возможности нанять дачу, -- всё это разом неприятно потрясло и без того уже расстроенные нервы юноши. Нестерпимая же вонь из распивочных, которых в этой части города особенное множество, и пьяные, поминутно попадавшиеся, несмотря на буднее время, довершили отвратительный и грустный колорит картины. Чувство глубочайшего омерзения мелькнуло на миг в тонких чертах молодого человека. Кстати, он был замечательно хорош собою, с прекрасными темными глазами, темно-рус, ростом выше среднего, тонок и строен. Но скоро он впал как бы в глубокую задумчивость, даже, вернее сказать, как бы в какое-то забытье, и пошел, уже не замечая окружающего, да и не желая его замечать. Изредка только бормотал он что-то про себя, от своей привычки к монологам, в которой он сейчас сам себе признался. В эту же минуту он и сам сознавал, что мысли его порою мешаются и что он очень слаб: второй день как уж он почти совсем ничего не ел. +# Он был до того худо одет, что иной, даже и привычный человек, посовестился бы днем выходить в таких лохмотьях на улицу. Впрочем, квартал был таков, что костюмом здесь было трудно кого-нибудь удивить. Близость Сенной, обилие известных заведений и, по преимуществу, цеховое и ремесленное население, скученное в этих серединных петербургских улицах и переулках, пестрили иногда общую панораму такими субъектами, что странно было бы и удивляться при встрече с иною фигурой. Но столько злобного презрения уже накопилось в душе молодого человека, что, несмотря на всю свою, иногда очень молодую, щекотливость, он менее всего совестился своих лохмотьев на улице. Другое дело при встрече с иными знакомыми или с прежними товарищами, с которыми вообще он не любил встречаться... А между тем, когда один пьяный, которого неизвестно почему и куда провозили в это время по улице в огромной телеге, запряженной огромною ломовою лошадью, крикнул ему вдруг, проезжая: "Эй ты, немецкий шляпник!" -- и заорал во всё горло, указывая на него рукой, -- молодой человек вдруг остановился и судорожно схватился за свою шляпу. Шляпа эта была высокая, круглая, циммермановская, но вся уже изношенная, совсем рыжая, вся в дырах и пятнах, без полей и самым безобразнейшим углом заломившаяся на сторону. Но не стыд, а совсем другое чувство, похожее даже на испуг, охватило его. +# "Я так и знал! -- бормотал он в смущении, -- я так и думал! Это уж всего сквернее! Вот эдакая какая-нибудь глупость, какая-нибудь пошлейшая мелочь, весь замысел может испортить! Да, слишком приметная шляпа... Смешная, потому и приметная... К моим лохмотьям непременно нужна фуражка, хотя бы старый блин какой-нибудь, а не этот урод. Никто таких не носит, за версту заметят, запомнят... главное, потом запомнят, ан и улика. Тут нужно быть как можно неприметнее... Мелочи, мелочи главное!.. Вот эти-то мелочи и губят всегда и всё..." +# # '; # -------------------------------------------------- # commit; @@ -267,34 +268,34 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # set list on; # set echo off; # select 'Metadata created OK.' as msg from rdb$database; -# +# # ''' % dict(globals(), **locals()) -# -# +# +# # f_checksql = open( os.path.join(context['temp_directory'], 'tmp_0986_w1251.sql'), 'w' ) # f_checksql.write( non_ascii_ddl.decode('utf8').encode('cp1251') ) # flush_and_close( f_checksql ) -# +# # # Result: file 'tmp_0986_w1251' is encoded in cp1251 and contains SQL statements to be executed. -# +# # ########################################################################################################### # ### check-1: attempt to apply DDL with non-ascii characters __WITHOUT__ charset specifying (for ISQL) ### # ########################################################################################################### -# +# # f_apply_cset_none_log = open( os.path.join(context['temp_directory'],'tmp_0986_apply_cset_none.log'), 'w') # f_apply_cset_none_err = open( os.path.join(context['temp_directory'],'tmp_0986_apply_cset_none.err'), 'w') -# +# # subprocess.call( [ context['isql_path'], "-q", "-i", f_checksql.name ], # stdout = f_apply_cset_none_log, # stderr = f_apply_cset_none_err # ) -# +# # # This file should contain only FIRST statement from DDL hich contains non-ascii characters: # # (because of 'set BAIL on' ISQL should immediately terminate its job): # # create collation "Циферки" for utf8 from unicode case insensitive 'NUMERIC-SORT=1';: # # # flush_and_close( f_apply_cset_none_log ) -# +# # # This file should contain error on 1st DDL statement which contains non-ascii characters: # # FB 3.x: # # Statement failed, SQLSTATE = 22000 @@ -307,29 +308,29 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # # -Cannot transliterate character between character sets # # # flush_and_close( f_apply_cset_none_err ) -# +# # ############################################################################################################# # ### check-2: attempt to apply DDL with non-ascii characters ___WITH___ specifying: ISQL ... -ch WIN1251 ### # ############################################################################################################# -# +# # f_apply_cset_1251_log = open( os.path.join(context['temp_directory'],'tmp_0986_apply_cset_1251.log'), 'w') # f_apply_cset_1251_err = open( os.path.join(context['temp_directory'],'tmp_0986_apply_cset_1251.err'), 'w') -# +# # subprocess.call( [ context['isql_path'], "-q", "-i", f_checksql.name, "-ch", "win1251" ], # stdout = f_apply_cset_1251_log, # stderr = f_apply_cset_1251_err # ) -# +# # # This file should contain ALL applied statements, plus final message: # # MSG Metadata created OK. # flush_and_close( f_apply_cset_1251_log ) -# +# # # This file should NOT contain any errors: # flush_and_close( f_apply_cset_1251_err ) -# +# # # CHECK RESULTS: # ################ -# +# # # This stdout log should contain only ONE statement (create collation ...), # # this DDL failed and caused ISQL to immediately terminate: # # @@ -341,7 +342,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # print( out_txt + "FOUND EXPECTED 'CREATE COLLATION STATEMENT'" ) # else: # print( out_txt+'SOME OTHER STATEMENT FOUND' ) -# +# # with open( f_apply_cset_none_err.name, 'r') as f: # for line in f: # out_txt='STDERR WHEN CSET=NONE: '; @@ -350,13 +351,13 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # print( out_txt+'FOUND EXPECTED SQLSTATE IN ERROR MESSAGE' ) # else: # print( out_txt+'SOME OTHER ERROR FOUND: '+line ) -# +# # # This log should contain 'magic text' which tells that all finished OK: # # MSG Metadata created OK. -# +# # if 'Metadata created OK.' in open(f_apply_cset_1251_log.name).read(): # print('STDLOG WHEN CSET=1251: ALL FINISHED OK.') -# +# # # This log should be EMPTY: when we used '-ch win1251' then metadata # # with non-ascii names in DB objects should be created successfully: # # @@ -364,25 +365,202 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # for line in f: # if line: # print('Unexpected STDERR when use -ch win1251: ' + line) -# +# # # CLEANUP # ######### # time.sleep(1) # cleanup( ( f_apply_cset_none_log, f_apply_cset_none_err, f_apply_cset_1251_log, f_apply_cset_1251_err,f_checksql, ) ) -# -# +# +# #--- #act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1) -expected_stdout_1 = """ - STDLOG WHEN CSET=NONE: FOUND EXPECTED 'CREATE COLLATION STATEMENT' - STDERR WHEN CSET=NONE: FOUND EXPECTED SQLSTATE IN ERROR MESSAGE - STDLOG WHEN CSET=1251: ALL FINISHED OK. - """ +act_1 = python_act('db_1', substitutions=substitutions_1) + +expected_stdout_1_a = """create collation "Циферки" for utf8 from unicode case insensitive 'NUMERIC-SORT=1';""" + +expected_stderr_1_a_40 = """ +Statement failed, SQLSTATE = 22018 +arithmetic exception, numeric overflow, or string truncation +-Cannot transliterate character between character sets +After line 4 in file /tmp/pytest/pytest-124/test/non_ascii_ddl.sql +""" + +expected_stderr_1_a_30 = """ +Statement failed, SQLSTATE = 22000 +unsuccessful metadata update +-CREATE COLLATION Циферки failed +-Malformed string +""" + +non_ascii_ddl=''' + set bail on; + + set echo on; + + create collation "Циферки" for utf8 from unicode case insensitive 'NUMERIC-SORT=1'; + create collation "Испания" for iso8859_1 from es_es_ci_ai 'SPECIALS-FIRST=1';; + commit; + + create domain "ИД'шники" int; + create domain "Группы" varchar(30) check( value in ('Электрика', 'Ходовая', 'Арматурка', 'Кузовщина') ); + create domain "Артикулы" varchar(12) character set utf8 check( value = upper(value) ) + collate "Циферки" -- enabled since core-5220 was fixed (30.04.2016) + ; + create domain "Комрады" varchar(40) character set iso8859_1 + collate "Испания" -- enabled since core-5220 was fixed (30.04.2016) + ; + create domain "Кол-во" numeric(12,3) not null; + + create sequence generilka; + create sequence "Генерилка"; + + create role "манагер"; + create role "начсклд"; + + -- TEMPLY COMMENTED UNTIL CORE-5209 IS OPEN: + -- ISQL -X ignores connection charset for text of EXCEPTION message (restoring it in initial charset when exception was created) + recreate exception "Невзлет" 'Запись обломалась, ваши не пляшут. Но не стесняйтесь и обязательно заходите еще, мы всегда рады видеть вас. До скорой встречи, товарищ!'; + commit; + + ------------------------------------------------- + recreate table "склад" ( + "ИД'шник" "ИД'шники" + ,"Откудова" "Группы" + ,"Номенклатура" "Артикулы" + ,"ИД'родителя" "ИД'шники" + ,"сколько там" "Кол-во" + ,constraint "ПК-ИД'шник" primary key ("ИД'шник") using index "склад_ПК" + ,constraint "ФК-на-родока" foreign key("ИД'родителя") references "склад" ("ИД'шник") using index "склад_ФК" + ,constraint "остаток >=0" check ("сколько там" >= 0) + ); + + recreate view "Электрика"("ид изделия", "Название", "Запас") as + select + "ИД'шник" + ,"Номенклатура" + ,"сколько там" + from "склад" + where "Откудова" = 'Электрика' + ; + + set term ^; + create or alter trigger "склад би" for "склад" active before insert as + begin + --new."ИД'шник" = coalesce( new."ИД'шник", gen_id(generilka, 1) ); + -- not avail up to 2.5.6: + new."ИД'шник" = coalesce( new."ИД'шник", gen_id("Генерилка", 1) ); + end + ^ + + create or alter procedure "Доб на склад"( + "Откудова" varchar(30) + ,"Номенклатура" varchar(30) + ,"ИД'родителя" int + ,"сколько там" numeric(12,3) + ) returns ( + "код возврата" int + ) as + begin + insert into "склад"( + "Откудова" + ,"Номенклатура" + ,"ИД'родителя" + ,"сколько там" + ) values ( + :"Откудова" + ,:"Номенклатура" + ,:"ИД'родителя" + ,:"сколько там" + ); + + end + ^ + create or alter procedure "Удалить" as + begin + /* + Антон Павлович Чехов. Каштанка + + 1. Дурное поведение + + Молодая рыжая собака - помесь такса с дворняжкой - очень похожая мордой + на лисицу, бегала взад и вперед по тротуару и беспокойно оглядывалась по + сторонам. Изредка она останавливалась и, плача, приподнимая то одну озябшую + лапу, то другую, старалась дать себе отчет: как это могло случиться, что она + заблудилась? + */ + end + ^ + set term ;^ + + grant select on "склад" to "манагер"; + grant select, insert, update, delete on "склад" to "начсклд"; + -- no avail in 2.0: grant execute procedure "Доб на склад" to "начсклд"; + + + comment on sequence "Генерилка" is 'Генератор простых идей'; + comment on table "склад" is 'Это всё, что мы сейчас имеем в наличии'; + comment on view "Электрика" is 'Не суй пальцы в розетку, будет бо-бо!'; + comment on procedure "Доб на склад" is 'Процедурка добавления изделия на склад'; + comment on parameter "Доб на склад"."Откудова" is 'Группа изделия, которое собираемся добавить'; + + comment on parameter "Доб на склад"."ИД'родителя" is ' + Федор Михайлович Достоевский + + Преступление и наказание + + Роман в шести частях с эпилогом + + + Часть первая + + I + В начале июля, в чрезвычайно жаркое время, под вечер, один молодой человек вышел из своей каморки, которую нанимал от жильцов в С -- м переулке, на улицу и медленно, как бы в нерешимости, отправился к К -- ну мосту. + Он благополучно избегнул встречи с своею хозяйкой на лестнице. Каморка его приходилась под самою кровлей высокого пятиэтажного дома и походила более на шкаф, чем на квартиру. Квартирная же хозяйка его, у которой он нанимал эту каморку с обедом и прислугой, помещалась одною лестницей ниже, в отдельной квартире, и каждый раз, при выходе на улицу, ему непременно надо было проходить мимо хозяйкиной кухни, почти всегда настежь отворенной на лестницу. И каждый раз молодой человек, проходя мимо, чувствовал какое-то болезненное и трусливое ощущение, которого стыдился и от которого морщился. Он был должен кругом хозяйке и боялся с нею встретиться. + Не то чтоб он был так труслив и забит, совсем даже напротив; но с некоторого времени он был в раздражительном и напряженном состоянии, похожем на ипохондрию. Он до того углубился в себя и уединился от всех, что боялся даже всякой встречи, не только встречи с хозяйкой. Он был задавлен бедностью; но даже стесненное положение перестало в последнее время тяготить его. Насущными делами своими он совсем перестал и не хотел заниматься. Никакой хозяйки, в сущности, он не боялся, что бы та ни замышляла против него. Но останавливаться на лестнице, слушать всякий вздор про всю эту обыденную дребедень, до которой ему нет никакого дела, все эти приставания о платеже, угрозы, жалобы, и при этом самому изворачиваться, извиняться, лгать, -- нет уж, лучше проскользнуть как-нибудь кошкой по лестнице и улизнуть, чтобы никто не видал. + Впрочем, на этот раз страх встречи с своею кредиторшей даже его самого поразил по выходе на улицу. + "На какое дело хочу покуситься и в то же время каких пустяков боюсь! -- подумал он с странною улыбкой. -- Гм... да... всё в руках человека, и всё-то он мимо носу проносит, единственно от одной трусости... это уж аксиома... Любопытно, чего люди больше всего боятся? Нового шага, нового собственного слова они всего больше боятся... А впрочем, я слишком много болтаю. Оттого и ничего не делаю, что болтаю. Пожалуй, впрочем, и так: оттого болтаю, что ничего не делаю. Это я в этот последний месяц выучился болтать, лежа по целым суткам в углу и думая... о царе Горохе. Ну зачем я теперь иду? Разве я способен на это? Разве это серьезно? Совсем не серьезно. Так, ради фантазии сам себя тешу; игрушки! Да, пожалуй что и игрушки!" + На улице жара стояла страшная, к тому же духота, толкотня, всюду известка, леса, кирпич, пыль и та особенная летняя вонь, столь известная каждому петербуржцу, не имеющему возможности нанять дачу, -- всё это разом неприятно потрясло и без того уже расстроенные нервы юноши. Нестерпимая же вонь из распивочных, которых в этой части города особенное множество, и пьяные, поминутно попадавшиеся, несмотря на буднее время, довершили отвратительный и грустный колорит картины. Чувство глубочайшего омерзения мелькнуло на миг в тонких чертах молодого человека. Кстати, он был замечательно хорош собою, с прекрасными темными глазами, темно-рус, ростом выше среднего, тонок и строен. Но скоро он впал как бы в глубокую задумчивость, даже, вернее сказать, как бы в какое-то забытье, и пошел, уже не замечая окружающего, да и не желая его замечать. Изредка только бормотал он что-то про себя, от своей привычки к монологам, в которой он сейчас сам себе признался. В эту же минуту он и сам сознавал, что мысли его порою мешаются и что он очень слаб: второй день как уж он почти совсем ничего не ел. + Он был до того худо одет, что иной, даже и привычный человек, посовестился бы днем выходить в таких лохмотьях на улицу. Впрочем, квартал был таков, что костюмом здесь было трудно кого-нибудь удивить. Близость Сенной, обилие известных заведений и, по преимуществу, цеховое и ремесленное население, скученное в этих серединных петербургских улицах и переулках, пестрили иногда общую панораму такими субъектами, что странно было бы и удивляться при встрече с иною фигурой. Но столько злобного презрения уже накопилось в душе молодого человека, что, несмотря на всю свою, иногда очень молодую, щекотливость, он менее всего совестился своих лохмотьев на улице. Другое дело при встрече с иными знакомыми или с прежними товарищами, с которыми вообще он не любил встречаться... А между тем, когда один пьяный, которого неизвестно почему и куда провозили в это время по улице в огромной телеге, запряженной огромною ломовою лошадью, крикнул ему вдруг, проезжая: "Эй ты, немецкий шляпник!" -- и заорал во всё горло, указывая на него рукой, -- молодой человек вдруг остановился и судорожно схватился за свою шляпу. Шляпа эта была высокая, круглая, циммермановская, но вся уже изношенная, совсем рыжая, вся в дырах и пятнах, без полей и самым безобразнейшим углом заломившаяся на сторону. Но не стыд, а совсем другое чувство, похожее даже на испуг, охватило его. + "Я так и знал! -- бормотал он в смущении, -- я так и думал! Это уж всего сквернее! Вот эдакая какая-нибудь глупость, какая-нибудь пошлейшая мелочь, весь замысел может испортить! Да, слишком приметная шляпа... Смешная, потому и приметная... К моим лохмотьям непременно нужна фуражка, хотя бы старый блин какой-нибудь, а не этот урод. Никто таких не носит, за версту заметят, запомнят... главное, потом запомнят, ан и улика. Тут нужно быть как можно неприметнее... Мелочи, мелочи главное!.. Вот эти-то мелочи и губят всегда и всё..." + + '; + -------------------------------------------------- + commit; + --/* + --TEMPLY COMMENTED UNTIL CORE-5221 IS OPEN: + set echo on; + show collation; + show domain; + show exception; -- <<<<<<<<<<<<< + show sequence; + show table; + show trigger; + show view; + show procedure; + show role; + --*/ + set list on; + set echo off; + select 'Metadata created OK.' as msg from rdb$database; + ''' + + +tmp_file_1 = temp_file('non_ascii_ddl.sql') @pytest.mark.version('>=3.0') -@pytest.mark.xfail -def test_1(db_1): - pytest.fail("Test not IMPLEMENTED") +def test_1(act_1: Action, tmp_file_1: Path): + # + tmp_file_1.write_bytes(non_ascii_ddl.encode('cp1251')) + # run without specifying charset + act_1.expected_stdout = expected_stdout_1_a + act_1.expected_stderr = expected_stderr_1_a_40 if act_1.is_version('>=4.0') else expected_stderr_1_a_30 + act_1.isql(switches=['-q'], input_file=tmp_file_1, charset=None, io_enc='cp1251') + assert act_1.clean_stdout == act_1.clean_expected_stdout + assert act_1.clean_stderr == act_1.clean_expected_stderr + # run with charset + act_1.reset() + act_1.isql(switches=['-q'], input_file=tmp_file_1, charset='win1251', io_enc='cp1251') + assert act_1.clean_stdout.endswith('Metadata created OK.') diff --git a/tests/bugs/core_1073_test.py b/tests/bugs/core_1073_test.py index 86f6ea82..6900e4d1 100644 --- a/tests/bugs/core_1073_test.py +++ b/tests/bugs/core_1073_test.py @@ -2,14 +2,14 @@ # # id: bugs.core_1073 # title: SINGULAR buggy when nulls present -# decription: +# decription: # tracker_id: CORE-1073 # min_versions: [] # versions: 2.1 # qmid: bugs.core_1073 import pytest -from firebird.qa import db_factory, isql_act, Action +from firebird.qa import db_factory, python_act, Action # version: 2.1 # resources: None @@ -30,82 +30,153 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # if (exp and (r is None)) or (not exp and (r is not None)): # print ('Test FAILED in step ',step,', expectation ',exp) # print ('Statement:',statement) -# +# # c = db_conn.cursor() # p_singular = 'select 1 from rdb$database where singular(select * from t where a = 1)' # n_singular = 'select 1 from rdb$database where not(singular(select * from t where a = 1))' # p_nsingular = 'select 1 from rdb$database where not singular( select * from t where a = 1)' # n_nsingular = 'select 1 from rdb$database where not(not singular(select * from t where a = 1))' -# +# # ins = 'insert into t values (%s)' -# +# # # Step 1 -# +# # c.execute(ins % '2') # c.execute(ins % 'null') # db_conn.commit() -# +# # check(1,c,p_singular,False) # check(1,c,n_singular,True) # check(1,c,p_nsingular,True) # check(1,c,n_nsingular,False) -# +# # c.execute('delete from t') # db_conn.commit() -# +# # # Step 2 -# +# # c.execute(ins % '1') # c.execute(ins % 'null') # db_conn.commit() -# +# # check(2,c,p_singular,True) # check(2,c,n_singular,False) # check(2,c,p_nsingular,False) # check(2,c,n_nsingular,True) -# +# # c.execute('delete from t') # db_conn.commit() -# +# # # Step 3 -# +# # c.execute(ins % '1') # c.execute(ins % 'null') # c.execute(ins % '1') # db_conn.commit() -# +# # check(3,c,p_singular,False) # check(3,c,n_singular,True) # check(3,c,p_nsingular,True) # check(3,c,n_nsingular,False) -# +# # c.execute('delete from t') # db_conn.commit() -# +# # # Step 4 -# +# # c.execute(ins % '1') # c.execute(ins % '1') # c.execute(ins % 'null') # db_conn.commit() -# +# # check(4,c,p_singular,False) # check(4,c,n_singular,True) # check(4,c,p_nsingular,True) # check(4,c,n_nsingular,False) -# +# # c.execute('delete from t') # db_conn.commit() -# -# -# +# +# +# #--- -#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1) +act_1 = python_act('db_1', substitutions=substitutions_1) + +def check(step, cur, statement, exp): + r = cur.execute(statement).fetchone() + if (exp and (r is None)) or (not exp and (r is not None)): + pytest.fail(f'Test FAILED in step {step}, expectation {exp}') @pytest.mark.version('>=2.1') -@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() + # + p_singular = 'select 1 from rdb$database where singular(select * from t where a = 1)' + n_singular = 'select 1 from rdb$database where not(singular(select * from t where a = 1))' + p_nsingular = 'select 1 from rdb$database where not singular( select * from t where a = 1)' + n_nsingular = 'select 1 from rdb$database where not(not singular(select * from t where a = 1))' + # + ins = 'insert into t values (%s)' + # + # Step 1 + # + c.execute(ins % '2') + c.execute(ins % 'null') + con.commit() + # + check(1, c, p_singular, False) + check(1, c, n_singular, True) + check(1, c, p_nsingular, True) + check(1, c, n_nsingular, False) + # + c.execute('delete from t') + con.commit() + # + # Step 2 + # + c.execute(ins % '1') + c.execute(ins % 'null') + con.commit() + # + check(2, c, p_singular, True) + check(2, c, n_singular, False) + check(2, c, p_nsingular, False) + check(2, c, n_nsingular, True) + # + c.execute('delete from t') + con.commit() + # + # Step 3 + # + c.execute(ins % '1') + c.execute(ins % 'null') + c.execute(ins % '1') + con.commit() + # + check(3, c, p_singular, False) + check(3, c, n_singular, True) + check(3, c, p_nsingular, True) + check(3, c, n_nsingular, False) + # + c.execute('delete from t') + con.commit() + # + # Step 4 + # + c.execute(ins % '1') + c.execute(ins % '1') + c.execute(ins % 'null') + con.commit() + # + check(4, c, p_singular, False) + check(4, c, n_singular, True) + check(4, c, p_nsingular, True) + check(4, c, n_nsingular, False) + # + c.execute('delete from t') + con.commit() + diff --git a/tests/bugs/core_1076_test.py b/tests/bugs/core_1076_test.py index 3750f7fa..daccb47e 100644 --- a/tests/bugs/core_1076_test.py +++ b/tests/bugs/core_1076_test.py @@ -2,20 +2,20 @@ # # id: bugs.core_1076 # title: gsec truncate First.Middle.Last Name fields to 17 chars instead of 32 chars available in field definition -# decription: +# decription: # FB2.0 correctly saves First, Middle & Last Name fields in the security database to the available length of 32 characters. # FB1.5.3 and still now FB1.5.4RC1 truncates these field lengths to 17 chars. # --- # 11.01.2016: refactored for 3.0: use FBSVCMGR instead of GSEC. This was agreed with Alex, see his reply 11.01.2015 17:57. -# -# +# +# # tracker_id: CORE-1076 # min_versions: [] # 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 @@ -33,52 +33,52 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # import subprocess # from subprocess import Popen # from fdb import services -# +# # 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 )): # if os.path.isfile( f_names_list[i]): # os.remove( f_names_list[i] ) -# +# # #-------------------------------------------- -# +# # 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() -# +# # check_login="Nebuchadnezzar2_King_of_Babylon" -# +# # f_svc_log=open( os.path.join(context['temp_directory'],'tmp_1076_fbsvc.log'), 'w') # f_svc_err=open( os.path.join(context['temp_directory'],'tmp_1076_fbsvc.err'), 'w') -# +# # f_svc_log.write("Try to add user.") # f_svc_log.write("\\n") # f_svc_log.seek(0,2) -# +# # subprocess.call( [ context['fbsvcmgr_path'] # ,"localhost:service_mgr" # ,"action_add_user" @@ -88,13 +88,13 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # ] # ,stdout=f_svc_log, stderr=f_svc_err # ) -# +# # 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" @@ -106,83 +106,95 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # ] # ,stdout=f_svc_log, stderr=f_svc_err # ) -# +# # 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 ) -# -# isql_txt=''' set list on; -# select sec$user_name, sec$first_name, sec$middle_name, sec$last_name from sec$users +# +# isql_txt=''' set list on; +# select sec$user_name, sec$first_name, sec$middle_name, sec$last_name from sec$users # where upper(sec$user_name) = upper('%s'); # commit; # drop user %s; # ''' % (check_login, check_login) -# +# # f_sql_txt=open( os.path.join(context['temp_directory'],'tmp_1076_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_1076_isql.log'), 'w') # f_sql_err=open( os.path.join(context['temp_directory'],'tmp_1076_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 ) -# +# # 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 ) -# +# # 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 ) -# +# # 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 ) -# +# # ############################################# -# +# # # 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. - SVC STDOUT: Try to modify user: change password and some attributes. - SVC STDOUT: All done. - SQL STDOUT: SEC$USER_NAME NEBUCHADNEZZAR2_KING_OF_BABYLON - SQL STDOUT: SEC$FIRST_NAME Nebuchadnezzar3_King_of_Babylon - SQL STDOUT: SEC$MIDDLE_NAME Nebuchadnezzar4_King_of_Babylon - SQL STDOUT: SEC$LAST_NAME Nebuchadnezzar5_King_of_Babylon - """ +SEC$USER_NAME NEBUCHADNEZZAR2_KING_OF_BABYLON +SEC$FIRST_NAME Nebuchadnezzar3_King_of_Babylon +SEC$MIDDLE_NAME Nebuchadnezzar4_King_of_Babylon +SEC$LAST_NAME Nebuchadnezzar5_King_of_Babylon +""" @pytest.mark.version('>=3.0') -@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: + check_login = "Nebuchadnezzar2_King_of_Babylon" + srv.user.add(user_name=check_login, password="Nebu_King_of_Babylon") + srv.user.update(user_name=check_login, + first_name="Nebuchadnezzar3_King_of_Babylon", + middle_name="Nebuchadnezzar4_King_of_Babylon", + last_name="Nebuchadnezzar5_King_of_Babylon") + # + act_1.script = f"""set list on; +select sec$user_name, sec$first_name, sec$middle_name, sec$last_name from sec$users +where upper(sec$user_name) = upper('{check_login}'); +commit; +drop user {check_login}; +""" + act_1.expected_stdout = expected_stdout_1 + act_1.execute() + assert act_1.clean_stdout == act_1.clean_expected_stdout diff --git a/tests/bugs/core_1112_test.py b/tests/bugs/core_1112_test.py index a74f8cec..0384b57f 100644 --- a/tests/bugs/core_1112_test.py +++ b/tests/bugs/core_1112_test.py @@ -9,7 +9,7 @@ # qmid: bugs.core_1112 import pytest -from firebird.qa import db_factory, isql_act, Action +from firebird.qa import db_factory, python_act, Action # version: 2.1 # resources: None @@ -28,7 +28,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # c.execute("select * from rdb$database where '%s' = 'a'" % longstr) # except: # pass -# +# # try: # c.execute("select * from rdb$database where '%s' containing 'a'" % longstr) # except: @@ -36,14 +36,18 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # c.execute("select 'a' from rdb$database") # print (c.fetchall()) #--- -#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1) -expected_stdout_1 = """[('a',)] -""" +act_1 = python_act('db_1', substitutions=substitutions_1) @pytest.mark.version('>=2.1') -@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() + longstr = 'abc' * 10930 + c.execute(f"select * from rdb$database where '{longstr}' = 'a'") + c.execute(f"select * from rdb$database where '{longstr}' containing 'a'") + c.execute("select 'a' from rdb$database") + result = c.fetchall() + assert result == [('a',)] diff --git a/tests/bugs/core_1148_test.py b/tests/bugs/core_1148_test.py index dd1a5d1f..053aeeae 100644 --- a/tests/bugs/core_1148_test.py +++ b/tests/bugs/core_1148_test.py @@ -2,7 +2,7 @@ # # id: bugs.core_1148 # title: Every user can view server log using services API -# decription: +# decription: # Instead of usage 'resource:test_user' (as it was before) we create every time this test run user TMP$C1148 # and make test connect to database as this user in order to check ability to connect and get engine version. # Then we parse engine version (is it 2.5 or 3.0 ?) and construct command to obtain Firebird log using FBSVCMGR @@ -10,19 +10,22 @@ # After that we try to extract firebird log using fbsvcmgr and this command is EXPECTED return error, so we log # this message to separate file (and STDOUT is redirected to /dev/null). # Finally, we check content of 1st and 2nd files and remove temply created user. -# +# # tracker_id: CORE-1148 # min_versions: ['2.5.0'] # versions: 2.5 # qmid: bugs.core_1148 import pytest -from firebird.qa import db_factory, isql_act, Action +from firebird.qa import db_factory, python_act, Action, temp_user, User +from firebird.driver import DatabaseError # version: 2.5 # resources: None -substitutions_1 = [('ENGINE_VERSION .*', 'ENGINE_VERSION'), ('STDERR: UNABLE TO PERFORM OPERATION.*', 'STDERR: UNABLE TO PERFORM OPERATION'), ('STDERR: -YOU MUST HAVE SYSDBA RIGHTS AT THIS SERVER*', '')] +substitutions_1 = [('ENGINE_VERSION .*', 'ENGINE_VERSION'), + ('STDERR: UNABLE TO PERFORM OPERATION.*', 'STDERR: UNABLE TO PERFORM OPERATION'), + ('STDERR: -YOU MUST HAVE SYSDBA RIGHTS AT THIS SERVER*', '')] init_script_1 = """""" @@ -30,35 +33,35 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # test_script_1 #--- -# -# +# +# # # Refactored 05-JAN-2016: removed dependency on recource 'test_user' because this lead to: # # UNTESTED: bugs.core_2729 # # Add new user # # Unexpected stderr stream received from GSEC. # # (i.e. test remained in state "Untested" because of internal error in gsec while creating user 'test' from resource). # # Checked on WI-V2.5.5.26952 (SC), WI-V3.0.0.32266 (SS/SC/CS). -# +# # import os # import subprocess # import time -# +# # # Obtain engine version: # engine = str(db_conn.engine_version) -# +# # db_conn.execute_immediate("create user tmp$c1148 password 'QweRtyUi'") # db_conn.commit() -# +# # if engine.startswith('2.5'): # get_firebird_log_key='action_get_ib_log' # else: # get_firebird_log_key='action_get_fb_log' -# +# # fn_nul = open(os.devnull, 'w') # fn_err=open( os.path.join(context['temp_directory'],'tmp_1148_get_fb_log.err'), 'w') # subprocess.call([ context['fbsvcmgr_path'], # "localhost:service_mgr", -# "user","TMP$C1148","password","QweRtyUi", +# "user","TMP$C1148","password","QweRtyUi", # get_firebird_log_key # ], # stdout=fn_nul, @@ -66,12 +69,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # ) # fn_nul.close() # fn_err.close() -# +# # # CLEANUP: drop user that was temp-ly created for this test: # ########## # db_conn.execute_immediate('drop user tmp$c1148') # db_conn.commit() -# +# # # Ouput error log: it should contain text about unable to perform operation. # # NB: text in FB 4.0 was splitted, phrase "You must have SYSDBA rights..." is # # printed on separate line. Checking for matching to this phrase can be skipped @@ -79,25 +82,26 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # with open( fn_err.name,'r') as f: # for line in f: # print("STDERR: "+line.upper()) -# -# # Do not remove this pause: on Windows closing of handles can take some (small) time. +# +# # Do not remove this pause: on Windows closing of handles can take some (small) time. # # Otherwise Windows(32) access error can raise here. # time.sleep(1) -# +# # if os.path.isfile(fn_err.name): # os.remove(fn_err.name) -# -# +# +# #--- -#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1) -expected_stdout_1 = """ - STDERR: UNABLE TO PERFORM OPERATION - """ +act_1 = python_act('db_1', substitutions=substitutions_1) + +user_1 = temp_user(name='TMP$C1148', password='QweRtyUi') @pytest.mark.version('>=2.5') -@pytest.mark.xfail -def test_1(db_1): - pytest.fail("Test not IMPLEMENTED") +def test_1(act_1: Action, user_1: User): + with act_1.connect_server(user=user_1.name, password=user_1.password) as srv: + with pytest.raises(DatabaseError, match='Unable to perform operation\n-You must have SYSDBA rights at this server'): + srv.info.get_log() + diff --git a/tests/bugs/core_1156_test.py b/tests/bugs/core_1156_test.py index 93f64e5f..6963f6b7 100644 --- a/tests/bugs/core_1156_test.py +++ b/tests/bugs/core_1156_test.py @@ -2,14 +2,14 @@ # # id: bugs.core_1156 # title: Prepare fails when having a parameter in a DSQL statement before a sub query -# decription: +# decription: # tracker_id: CORE-1156 # min_versions: [] # versions: 2.1 # qmid: bugs.core_1156 import pytest -from firebird.qa import db_factory, isql_act, Action +from firebird.qa import db_factory, python_act, Action # version: 2.1 # resources: None @@ -27,34 +27,52 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # c.prep('select count(*) from rdb$database where ? < (select count(*) from rdb$database)') # except: # print ('Test FAILED in case 1') -# +# # try: # c.prep('select count(*) from rdb$database where (select count(*) from rdb$database) > ?') # except: # print ('Test FAILED in case 2') -# +# # try: # c.prep('select count(*) from rdb$database where ? < cast ((select count(*) from rdb$database) as integer)') # except: # print ('Test FAILED in case 3') -# +# # try: # c.prep('select count(*) from rdb$database where 0 < (select count(*) from rdb$database)') # except: # print ('Test FAILED in case 4') -# +# # try: # c.prep('select count(*) from rdb$database where cast (? as integer) < (select count(*) from rdb$database)') # except: # print ('Test FAILED in case 5') -# +# #--- -#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') -@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() + try: + c.prepare('select count(*) from rdb$database where ? < (select count(*) from rdb$database)') + except: + pytest.fail('Test FAILED in case 1') + try: + c.prepare('select count(*) from rdb$database where (select count(*) from rdb$database) > ?') + except: + pytest.fail('Test FAILED in case 2') + try: + c.prepare('select count(*) from rdb$database where ? < cast ((select count(*) from rdb$database) as integer)') + except: + pytest.fail('Test FAILED in case 3') + try: + c.prepare('select count(*) from rdb$database where 0 < (select count(*) from rdb$database)') + except: + pytest.fail('Test FAILED in case 4') + try: + c.prepare('select count(*) from rdb$database where cast (? as integer) < (select count(*) from rdb$database)') + except: + pytest.fail('Test FAILED in case 5') diff --git a/tests/bugs/core_1175_test.py b/tests/bugs/core_1175_test.py index 7c4293f3..10d37104 100644 --- a/tests/bugs/core_1175_test.py +++ b/tests/bugs/core_1175_test.py @@ -2,30 +2,30 @@ # # id: bugs.core_1175 # title: Error "Data type unknown" when any UDF argument is a built-in function containing a DSQL parameter reference -# decription: +# decription: # For FB 2.5 and 3.x - this test uses UDF from ib_udf. -# +# # 24.01.2019. Added separate code for running on FB 4.0+. # UDF usage is deprecated in FB 4+, see: ".../doc/README.incompatibilities.3to4.txt". -# Functions div, frac, dow, sdow, getExactTimestampUTC and isLeapYear got safe replacement +# Functions div, frac, dow, sdow, getExactTimestampUTC and isLeapYear got safe replacement # in UDR library "udf_compat", see it in folder: ../plugins/udr/ -# +# # Checked on: # 4.0.0.1340: OK, 2.594s. # 4.0.0.1378: OK, 5.579s. -# +# # NOTE. Build 4.0.0.1172 (date: 25.08.2018) raises here: -# SQLCODE: -902... expression evaluation not supported... +# SQLCODE: -902... expression evaluation not supported... # Invalid data type for division in dialect 3 # gdscode = 335544569. -# +# # tracker_id: CORE-1175 # min_versions: [] # versions: 4.0 # qmid: bugs.core_1175 import pytest -from firebird.qa import db_factory, isql_act, Action +from firebird.qa import db_factory, python_act, Action # version: 4.0 # resources: None @@ -62,17 +62,18 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1) # except Exception,e: # print( 'Test FAILED!' ) # print( e ) -# +# #--- -#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1) -expected_stdout_1 = """ - Test PASSED! - """ +act_1 = python_act('db_1', substitutions=substitutions_1) @pytest.mark.version('>=4.0') -@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() + try: + c.prepare('select 1 from rdb$database where UDR40_frac(?) != UDR40_div(?, ?) / ?') + except: + pytest.fail('Test FAILED')