6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-23 05:53:06 +01:00
firebird-qa/tests/bugs/core_4126_test.py

342 lines
11 KiB
Python
Raw Normal View History

2021-04-26 20:07:00 +02:00
#coding:utf-8
#
# id: bugs.core_4126
# title: gbak -r fails in restoring all stored procedures/functions in packages
2021-11-18 20:15:37 +01:00
# decription:
2021-04-26 20:07:00 +02:00
# Test creates table and procedure + function - both standalone and packaged.
# Then we do (with saving result in logs):
# 1) checking query;
# 2) isql -x
# After this we try to backup and restore - STDERR should be empty.
2021-11-18 20:15:37 +01:00
# Finally, we try again to run checking query and extract metadata - and compare
# their result with previously stored one.
2021-04-26 20:07:00 +02:00
# Difference between them should be EMPTY with excluding name of databases.
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# tracker_id: CORE-4126
# min_versions: ['3.0']
# versions: 3.0
# qmid: None
import pytest
2021-11-18 20:15:37 +01:00
from io import BytesIO
from difflib import unified_diff
from firebird.qa import db_factory, python_act, Action
from firebird.driver import SrvRestoreFlag
2021-04-26 20:07:00 +02:00
# version: 3.0
# resources: None
2021-11-18 20:15:37 +01:00
substitutions_1 = [('CREATE DATABASE.*', 'CREATE DATABASE'),
('CREATE COLLATION .*', 'CREATE COLLATION')]
2021-04-26 20:07:00 +02:00
init_script_1 = """
create or alter procedure p01 as begin end;
create or alter function f01() returns int as begin end;
recreate package pg_01 as begin end;
commit;
recreate table test (x smallint);
commit;
set term ^;
execute block as
begin
begin
execute statement 'drop domain dm_nums';
when any do begin end
end
begin
execute statement 'drop collation nums_coll';
when any do begin end
end
end
^
set term ;^
commit;
create collation nums_coll for utf8 from unicode case insensitive 'NUMERIC-SORT=1';
create domain dm_nums as varchar(10) character set utf8 collate nums_coll;
commit;
recreate table test (id int, s dm_nums);
commit;
set term ^;
create or alter procedure p01(a_id int) returns (o_s type of dm_nums ) as
begin
for select reverse(s) from test where id = :a_id into o_s do suspend;
end
^
create or alter function f01(a_id int) returns dm_nums as
begin
return reverse((select s from test where id = :a_id));
end
^
2021-11-18 20:15:37 +01:00
recreate package pg_01 as
begin
2021-04-26 20:07:00 +02:00
procedure p01(a_id int) returns (o_s type of dm_nums );
function f01(a_id int) returns dm_nums;
end
^
create package body pg_01 as
begin
procedure p01(a_id int) returns (o_s type of dm_nums ) as
begin
for select s from test where id = :a_id into o_s do suspend;
end
function f01(a_id int) returns dm_nums as
begin
return (select s from test where id = :a_id);
end
end
^
set term ;^
commit;
insert into test(id, s) values(1, '1234');
insert into test(id, s) values(2, '125');
insert into test(id, s) values(3, '16');
commit;
2021-11-18 20:15:37 +01:00
"""
2021-04-26 20:07:00 +02:00
db_1 = db_factory(sql_dialect=3, init=init_script_1)
# test_script_1
#---
# import os
# import time
# import subprocess
# import difflib
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# db_file=db_conn.database_name
# db_conn.close()
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# #---------------------------------------------
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# def flush_and_close(file_handle):
# # https://docs.python.org/2/library/os.html#os.fsync
2021-11-18 20:15:37 +01:00
# # If you're starting with a Python file object f,
# # first do f.flush(), and
2021-04-26 20:07:00 +02:00
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
# global os
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# 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()
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# #--------------------------------------------
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# 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] )
# if os.path.isfile( f_names_list[i]):
# print('ERROR: can not remove file ' + f_names_list[i])
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# #--------------------------------------------
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# tmpfbk1=os.path.join(context['temp_directory'],'tmp_4126.fbk')
# if os.path.isfile(tmpfbk1):
# os.remove(tmpfbk1)
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# tmpfdb1=os.path.join(context['temp_directory'],'tmp_4126.fdb')
# if os.path.isfile(tmpfdb1):
# os.remove(tmpfdb1)
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# dml_test = ''' set list on;
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# select t.id, p.o_s as standalone_proc_result
# from test t left join p01(t.id) p on 1=1
# order by 2;
2021-11-18 20:15:37 +01:00
#
# select t.id, f01(t.id) as standalone_func_result from test t
2021-04-26 20:07:00 +02:00
# order by 2;
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# select t.id, p.o_s as packaged_proc_result
# from test t left join pg_01.p01(t.id) p on 1=1
# order by 2;
2021-11-18 20:15:37 +01:00
#
# select t.id, pg_01.f01(t.id) as packaged_func_result from test t
2021-04-26 20:07:00 +02:00
# order by 2;
# '''
# fbb=''
2021-11-18 20:15:37 +01:00
#
#
2021-04-26 20:07:00 +02:00
# # FIRST RUN DML_TEST
# ####################
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# f_run_dml_sql = open( os.path.join(context['temp_directory'],'tmp_4126_dml.sql'), 'w')
# f_run_dml_sql.write(dml_test)
# flush_and_close( f_run_dml_sql )
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# f_run_dml_log_1 = open( os.path.join(context['temp_directory'],'tmp_4126_dml_1.log'), 'w')
# subprocess.call( [context['isql_path'], dsn, "-i", f_run_dml_sql.name, "-ch", "utf8" ],
# stdout = f_run_dml_log_1,
# stderr = subprocess.STDOUT
# )
# flush_and_close( f_run_dml_log_1 )
2021-11-18 20:15:37 +01:00
#
#
2021-04-26 20:07:00 +02:00
# # EXTRACT METADATA-1
# ####################
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# f_extract_meta1_sql = open( os.path.join(context['temp_directory'],'tmp_4126_meta1.log'), 'w')
# subprocess.call( [context['isql_path'], dsn, "-x"],
# stdout = f_extract_meta1_sql,
# stderr = subprocess.STDOUT
# )
# flush_and_close( f_extract_meta1_sql )
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# # TRY TO BACKUP AND RESTORE
# ###########################
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# f_backup_log=open( os.path.join(context['temp_directory'],'tmp_4126_backup.log'), "w")
# f_backup_err=open( os.path.join(context['temp_directory'],'tmp_4126_backup.err'), "w")
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# subprocess.call([context['fbsvcmgr_path'],"localhost:service_mgr",
# "action_backup", "verbose",
# "dbname", db_file,
# "bkp_file", tmpfbk1
# ],
# stdout=f_backup_log, stderr=f_backup_err)
# flush_and_close( f_backup_log )
# flush_and_close( f_backup_err )
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# f_restore_log=open( os.path.join(context['temp_directory'],'tmp_4126_restore.log'), "w")
# f_restore_err=open( os.path.join(context['temp_directory'],'tmp_4126_restore.err'), "w")
# subprocess.call([context['fbsvcmgr_path'],"localhost:service_mgr",
# "action_restore", "res_replace", "verbose",
2021-11-18 20:15:37 +01:00
# "bkp_file", tmpfbk1,
# "dbname", tmpfdb1
2021-04-26 20:07:00 +02:00
# ],
# stdout=f_restore_log, stderr=f_restore_err)
# flush_and_close( f_restore_log )
# flush_and_close( f_restore_err )
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# # EXTRACT METADATA-2
# ####################
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# f_extract_meta2_sql = open( os.path.join(context['temp_directory'],'tmp_4126_meta2.log'), 'w')
# subprocess.call( [context['isql_path'], 'localhost:'+tmpfdb1, "-x"],
# stdout = f_extract_meta2_sql,
# stderr = subprocess.STDOUT
# )
# flush_and_close( f_extract_meta2_sql )
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# # AGAIN RUN DML_TEST
# ####################
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# f_run_dml_log_2 = open( os.path.join(context['temp_directory'],'tmp_4126_dml_2.log'), 'w')
# subprocess.call( [context['isql_path'], 'localhost:'+tmpfdb1, "-i", f_run_dml_sql.name, "-ch", "utf8" ],
# stdout = f_run_dml_log_2,
# stderr = subprocess.STDOUT
# )
# flush_and_close( f_run_dml_log_2 )
2021-11-18 20:15:37 +01:00
#
#
2021-04-26 20:07:00 +02:00
# # 7. CHECKS
# ###########
# # 1) STDERR for backup and restore - they all must be EMPTY.
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# f_list=[f_backup_err, f_restore_err]
# for i in range(len(f_list)):
# f_name=f_list[i].name
# if os.path.getsize(f_name) > 0:
# with open( f_name,'r') as f:
# for line in f:
# print("Unexpected STDERR, file "+f_name+": "+line)
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# # 2) diff between dml_1.log and dml_2.log should be EMPTY.
# # 3) diff between meta1.log and meta2.log should be EMPTY.
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# f_diff_txt=open( os.path.join(context['temp_directory'],'tmp_4126_diff.txt'), 'w')
# f_old=[]
# f_new=[]
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# f_old.append(f_extract_meta1_sql) # DDL: what we have BEFORE database backup
# f_old.append(f_run_dml_log_1) # DML: result of querying tables before DB backup
# f_new.append(f_extract_meta2_sql) # DDL: what we have AFTER database restore
# f_new.append(f_run_dml_log_2) # DML: result of querying tables AFTER database restore
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# for i in range(len(f_old)):
# old_file=open(f_old[i].name,'r')
# new_file=open(f_new[i].name,'r')
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# f_diff_txt.write( ''.join( difflib.unified_diff( old_file.readlines(), new_file.readlines() ) ) )
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# old_file.close()
# new_file.close()
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# flush_and_close( f_diff_txt )
2021-11-18 20:15:37 +01:00
#
2021-04-26 20:07:00 +02:00
# # Should be EMPTY:
# ##################
# with open( f_diff_txt.name,'r') as f:
# for line in f:
# if line.split() and not('---' in line or '+++' in line or '@@' in line or 'SET SQL DIALECT' in line or 'CREATE DATABASE' in line or 'collation'.upper() in line.upper()):
# print( 'Unexpected diff: ' + line )
2021-11-18 20:15:37 +01:00
#
#
2021-04-26 20:07:00 +02:00
# # Cleanup:
# ##########
# cleanup( [i.name for i in (f_backup_log, f_backup_err, f_restore_log, f_restore_err, f_extract_meta1_sql, f_extract_meta2_sql, f_run_dml_sql, f_run_dml_log_1, f_run_dml_log_2, f_diff_txt) ] )
2021-11-18 20:15:37 +01:00
#
# os.remove(tmpfdb1)
2021-04-26 20:07:00 +02:00
# os.remove(tmpfbk1)
2021-11-18 20:15:37 +01:00
#
#
2021-04-26 20:07:00 +02:00
#---
2021-11-18 20:15:37 +01:00
act_1 = python_act('db_1', substitutions=substitutions_1)
2021-04-26 20:07:00 +02:00
@pytest.mark.version('>=3.0')
2021-11-18 20:15:37 +01:00
def test_1(act_1: Action):
dml_test = '''
set list on;
select t.id, p.o_s as standalone_proc_result
from test t left join p01(t.id) p on 1=1
order by 2;
select t.id, f01(t.id) as standalone_func_result from test t
order by 2;
2021-04-26 20:07:00 +02:00
2021-11-18 20:15:37 +01:00
select t.id, p.o_s as packaged_proc_result
from test t left join pg_01.p01(t.id) p on 1=1
order by 2;
2021-04-26 20:07:00 +02:00
2021-11-18 20:15:37 +01:00
select t.id, pg_01.f01(t.id) as packaged_func_result from test t
order by 2;
'''
# gather metadta and test cript result before backup & restore
act_1.isql(switches=['-x'])
meta_before = act_1.stdout
act_1.reset()
act_1.isql(switches=[], input=dml_test)
dml_before = act_1.stdout
#
backup = BytesIO()
with act_1.connect_server() as srv:
srv.database.local_backup(database=str(act_1.db.db_path), backup_stream=backup)
backup.seek(0)
srv.database.local_restore(database=str(act_1.db.db_path), backup_stream=backup,
flags=SrvRestoreFlag.REPLACE)
# gather metadta and test cript result after backup & restore
act_1.reset()
act_1.isql(switches=['-x'])
meta_after = act_1.stdout
act_1.reset()
act_1.isql(switches=[], input=dml_test)
dml_after = act_1.stdout
# check
assert list(unified_diff(meta_before, meta_after)) == []
assert list(unified_diff(dml_before, dml_after)) == []