Утилита для поиска ошибок в системных таблицах
Привет всем.
Пользователь провайдера, о котором я упоминал в «Адском домене», асилил обновление системной таблицы RDB$FIELDS и наконец-то обрел счастье и душевную умиротворенность. Вообще говоря, эти проблемы с доменами текстовых колонок Interbase — стандартные. Я бы даже сказал, что вообще все баги и тупости InterBase — это тщательно запрограммированный функционал. По другому ведь никак 🙂
Ключевую роль в победе над ошибками RDB$FIELDS сыграл VBS-скрипт, текст которого я приведу полностью. Хотя он и достаточно большой. Его последнюю версию можно найти в дистрибутиве — это файл prog_check_system_tables.vbs
Сам скрипт в базе ничего не меняет. Он работает в «READ ONLY» транзакции, анализирует текстовые колонки и формирует два файла: общий лог и шаблон скрипта с SQL запросами для исправления.
На текущий момент скрипт обнаруживает такие ошибки:
— Отсутствие кодовой страницы у текстовой колонки. Будут сгенерированы запросы, в которые потом нужно будет руками прописать идентификатор кодовой страницы.
— Рассогласование длины текстовой колонки в байтах и в символах.
—-
Параметры подключения к базе прописаны в константах, которые находятся в самом начале текста скрипта.
Так что, если у вас MSSQL ругается страшными ошибками вида
Message 7356, Level 16, State 1, Line 2
The OLE DB «LCPI.IBProvider.3» for linked server «FBLINKED» supplied inconsistent metadata for column. The column «COMPANY_NAME»(which had the compile-time ordinal 4) of the object «GENERIC_TABLE_X» appears to have «length» equal to 25 at compile time and 27 at run time.
попробуйте выполнит этот скрипт — скорее всего он найдет причину и упростит процесс исправления.
На всякий случай я напомню — сначала экспериментируйте с исправлениями на тестовой базе данных.
option explicit
'---------------------------------------------------------
const c_db_location="localhost:d:\database\ibp_test_fb25_d3_2.gdb"
const c_db_user ="sysdba"
const c_db_pswd ="masterkey"
const c_db_client ="fbclient.dll"
const c_file_log ="check_system_tables.log"
const c_file_correct_sql ="check_system_tables.sql"
'---------------------------------------------------------
const c_sql__unk_value ="<???>"
'---------------------------------------------------------
'BLR Types
const c_isc_blr_dtype__text =14
const c_isc_blr_dtype__text2 =15
const c_isc_blr_dtype__short =7
const c_isc_blr_dtype__long =8
const c_isc_blr_dtype__quad =9
const c_isc_blr_dtype__int64 =16
const c_isc_blr_dtype__float =10
const c_isc_blr_dtype__double =27
const c_isc_blr_dtype__d_float =11
const c_isc_blr_dtype__timestamp =35
const c_isc_blr_dtype__varying =37
const c_isc_blr_dtype__varying2 =38
const c_isc_blr_dtype__blob =261
const c_isc_blr_dtype__cstring =40
const c_isc_blr_dtype__cstring2 =41
const c_isc_blr_dtype__blob_id =45
const c_isc_blr_dtype__sql_date =12
const c_isc_blr_dtype__sql_time =13
const c_ib7_blr_dtype__bool =17
const c_fb30_blr_dtype__bool =23
'---------------------------------------------------------
dim g_fso
dim g_file_log
dim g_file_correct_sql
dim g_intend
dim g_ctx
dim g_cn
dim g_err_count
dim g_processed__domains
'------
set g_fso =nothing
set g_file_log =nothing
set g_file_correct_sql=nothing
g_intend=0
set g_ctx =nothing
set g_cn =nothing
g_err_count=0
'---------------------------------------------------------
set g_fso=createobject("Scripting.FileSystemObject")
set g_file_log=g_fso.CreateTextFile(c_file_log,true)
'---------------------------------------------------------
set g_ctx=new tag_context
set g_cn=createobject("ADODB.Connection")
g_cn.Provider="LCPI.IBProvider.3"
g_cn.Properties("location") = c_db_location
g_cn.Properties("user id") = c_db_user
g_cn.Properties("password") = c_db_pswd
g_cn.Properties("dbclient_library") = c_db_client
call g_cn.Open()
call g_ctx.set_cn(g_cn)
'---------------------------------------------------------
print "DBMS Name: "&cstr_sn(g_cn.Properties("DBMS Name").Value)
print "DBMS Version: "&cstr_sn(g_cn.Properties("DBMS Version").Value)
print "DBMS Dialect: "&cstr_sn(g_cn.Properties("IB Database Dialect").Value)
'----------------------------------------------------------
call g_ctx.cn.Execute("SET TRANSACTION READ ONLY")
call load_db_charsets(g_ctx)
call add(g_err_count,check_table_columns(g_ctx))
call g_ctx.cn.Execute("COMMIT")
set g_file_correct_sql=g_fso.CreateTextFile(c_file_correct_sql,true)
call g_ctx.write_correct_sql_to_file(g_file_correct_sql)
print ""
print "TOTAL ERRORS: "&cstr(g_err_count)
call wscript.quit(g_err_count)
'----------------------------------------------------------
class tag_charset_data
public id
public name
public bytes_per_char
end class' tag_charset_data
'----------------------------------------------------------
private sub load_db_charsets(ctx)
print ""
print "load database charsets ..."
dim rs
set rs=ctx.cn.Execute _
("select rdb$character_set_name,"&vbCrLf&_
"rdb$character_set_id,"&vbCrLf&_
"rdb$bytes_per_character"&vbCrLf&_
"from rdb$character_sets")
dim db_csets_by_id
set db_csets_by_id=createobject("Scripting.Dictionary")
dim cset
dim msg
while(not rs.eof)
set cset=new tag_charset_data
cset.name =get_nn(rs,0)
cset.id =get_nn(rs,1)
cset.bytes_per_char =get_nn(rs,2)
if(db_csets_by_id.Exists(cset.id))then
msg="Detect multiple charsets with equal id ["&cset(cset.id)&"]"
call err.raise(-1,,msg)
end if
call db_csets_by_id.Add(cset.id,cset)
call rs.movenext()
wend
ctx.set_db_csets_by_id(db_csets_by_id)
end sub 'load_db_charsets
'----------------------------------------------------------
private function check_table_columns(ctx)
check_table_columns=0
print ""
print "check table columns ..."
dim rs
set rs=ctx.cn.Execute _
("select rdb$relation_name,rdb$view_blr from rdb$relations")
dim n_table
n_table=0
dim rel_name
dim rel_type
while(not rs.eof)
n_table=n_table+1
rel_name=get_nn(rs,0)
if(IsNull(rs(1).value))then
rel_type="TABLE"
else
rel_type="VIEW"
end if
print cstr(n_table)&". ["&rel_name&"] - {"&rel_type&"}"
call add(check_table_columns, _
check_table_columns__impl(ctx, _
rel_name, _
rel_type))
call rs.movenext()
wend
end function 'check_table_columns
'----------------------------------------------------------
private function check_table_columns__impl(ctx, _
relation_name, _
relation_type)
check_table_columns__impl=0
dim intend
set intend=add_intend(5)
dim cmd
dim rs
set cmd=createobject("ADODB.Command")
cmd.ActiveConnection=ctx.cn
cmd.CommandText= _
"select rf.rdb$field_name as column_name,"&vbCrLf& _
"f.*"&vbCrLf& _
"from rdb$relation_fields rf"&vbCrLf& _
"join rdb$fields f"&vbCrLf& _
"on rf.rdb$field_source=f.rdb$field_name"&vbCrLf& _
"where rf.rdb$relation_name=?"
cmd(0)=relation_name
set rs=cmd.Execute()
dim col_name
dim domain_data
dim n_col
n_col=0
while(not rs.eof)
n_col=n_col+1
col_name=get_nn(rs,"column_name")
print cstr(n_col)&". ["&col_name&"]"
set domain_data=new tag_domain_data
set domain_data.fields=rs.fields
domain_data.data_location="{"&relation_type&"}["&relation_name&"].["&col_name&"]"
set domain_data.sql_update_builder _
=new tag_sql_builder__update_domain_of_relation_fields
domain_data.sql_update_builder.relation_name =relation_name
domain_data.sql_update_builder.field_name =col_name
call add(check_table_columns__impl, _
check_domain_data(ctx,domain_data))
call rs.movenext()
wend
if(n_col=0)then
proces_error check_table_columns__impl, "No Columns!"
end if
end function 'check_table_columns__impl
'----------------------------------------------------------
class tag_domain_data
public fields
public data_location
public sql_update_builder
private sub class_initialize()
set fields=nothing
data_location=""
set sql_update_builder=nothing
end sub 'class_initialize
end class 'tag_domain_data
'----------------------------------------------------------
private function check_domain_data(ctx,data)
check_domain_data=0
dim intend
set intend=add_intend(5)
dim domain_name
domain_name=get_nn(data.fields,"RDB$FIELD_NAME")
if(not ctx.mark_domain_as_processed(domain_name))then
print "domain ["&domain_name&"] already processed"
exit function
end if
print "domain ["&domain_name&"]"
dim blr_type_id
blr_type_id=get_nn(data.fields,"rdb$field_type")
select case blr_type_id
case c_isc_blr_dtype__text
call add(check_domain_data,check_domain_data__text(ctx,data))
case c_isc_blr_dtype__varying
call add(check_domain_data,check_domain_data__varying(ctx,data))
case else
print "unknown data type"
end select
end function 'check_domain_data
'----------------------------------------------------------
private function check_domain_data__text(ctx,data)
check_domain_data__text=0
print "CHAR"
'-----------
dim msg
dim domain__name
dim domain__is_system
dim domain__cset_id
dim domain__field_length
dim domain__char_length
dim domain__cset
domain__name =get_nn(data.fields,"RDB$FIELD_NAME")
domain__is_system =get_value_or_default(data.fields,"RDB$SYSTEM_FLAG",0)<>0
domain__cset_id =data.fields("RDB$CHARACTER_SET_ID").value
domain__field_length =data.fields("RDB$FIELD_LENGTH").value
domain__char_length =data.fields("RDB$CHARACTER_LENGTH").value
set domain__cset=nothing
'-----------
dim valid_cset_id
dim valid_field_length
dim valid_char_length
valid_cset_id =true
valid_field_length =true
valid_char_length =true
'------------------------------- Check NOT NULL
if(IsNull(domain__cset_id))then
valid_cset_id=false
valid_char_length=false
process_error check_domain_data__text, "Column charset not defined"
end if
'-----------
if(IsNull(domain__field_length))then
valid_field_length=false
process_error check_domain_data__text, "Length in bytes not defined"
end if
'-----------
if(IsNull(domain__char_length))then
valid_char_length=false
if(not domain__is_system)then
process_error check_domain_data__text, "Length in chars not defined"
end if
end if
'------------------------------- Check charsetID
if(valid_cset_id)then
if(ctx.db_csets_by_id.Exists(domain__cset_id))then
set domain__cset=ctx.db_csets_by_id.Item(domain__cset_id)
else
valid_cset_id=false
process_error check_domain_data__text, "Unknown charsetID: "&cstr_sn(domain__cset_id)
end if
end if 'valid_cset_id
'-------------------------------- Check char length
if(valid_char_length and valid_cset_id and valid_field_length)then
if((domain__char_length*domain__cset.bytes_per_char)<>domain__field_length)then
valid_char_length=false
msg="Wrong char count: "&cstr_sn(domain__char_length)&". "& _
"BytesPerChar: "&cstr_sn(domain__cset.bytes_per_char)&". "& _
"FieldLength: "&cstr_sn(domain__field_length)
process_error check_domain_data__text, msg
end if
end if 'valid_char_length and valid_cset_id
'-------------------------------- Create correction SQL
dim comment
dim old_value
dim new_value
dim sql
dim sql_is_valid
'-------------------------------- SQL FOR RDB$FIELD_LENGTH
if(not valid_field_length)then
old_value=domain__field_length
sql_is_valid=valid_char_length and valid_cset_id
if(sql_is_valid)then
new_value=domain__char_length*domain__cset.bytes_per_char
else
new_value=c_sql__unk_value
end if
sql=data.sql_update_builder.gen(domain__name, _
"RDB$FIELD_LENGTH", _
old_value, _
new_value)
'----
comment="CHAR DOMAIN USED AT "&data.data_location
'----
call ctx.reg_correct_sql(sql_is_valid,sql,comment)
end if 'not valid_field_length
'-------------------------------- SQL FOR RDB$CHARACTER_LENGTH
if((not valid_char_length) and (not domain__is_system) and valid_cset_id)then
old_value=domain__char_length
if(not valid_field_length)then
sql_is_valid=false
else
sql_is_valid=((domain__field_length mod domain__cset.bytes_per_char)=0)
end if
if(sql_is_valid)then
new_value=domain__field_length / domain__cset.bytes_per_char
else
new_value=c_sql__unk_value
end if
sql=data.sql_update_builder.gen(domain__name, _
"RDB$CHARACTER_LENGTH", _
old_value, _
new_value)
comment="CHAR DOMAIN USED AT "&data.data_location
if(valid_cset_id)then
comment=comment&vbCrLf
comment=comment&"CSET_NAME : ["&domain__cset.name&"]"&vbCrLf
comment=comment&"CSET_ID : ["&domain__cset.id&"]"&vbCrLf
comment=comment&"BYTES_PER_CHAR : ["&domain__cset.bytes_per_char&"]"
end if
if(valid_field_length)then
comment=comment&vbCrLf
comment=comment&"FIELD_LENGTH : ["&domain__field_length&"]"&vbCrLf
end if
comment=comment&vbCrLf
comment=comment&"CURRENT CHAR_LENGTH: ["&cstr_sn(domain__char_length)&"]"
'----
call ctx.reg_correct_sql(sql_is_valid,sql,comment)
end if' not valid_char_length
'-------------------------------- SQL FOR RDB$CHARACTER_SET_ID
if(not valid_cset_id)then
old_value=domain__cset_id
new_value=c_sql__unk_value
sql=data.sql_update_builder.gen(domain__name, _
"RDB$CHARACTER_SET_ID", _
old_value, _
new_value)
sql_is_valid=false
comment="CHAR DOMAIN USED AT "&data.data_location
'----
call ctx.reg_correct_sql(sql_is_valid,sql,comment)
end if 'not valid_cset_id
end function 'check_domain_data__text
'----------------------------------------------------------
private function check_domain_data__varying(ctx,data)
check_domain_data__varying=0
print "VARCHAR"
'-----------
dim msg
dim domain__name
dim domain__is_system
dim domain__cset_id
dim domain__field_length
dim domain__char_length
dim domain__cset
domain__name =get_nn(data.fields,"RDB$FIELD_NAME")
domain__is_system =get_value_or_default(data.fields,"RDB$SYSTEM_FLAG",0)<>0
domain__cset_id =data.fields("RDB$CHARACTER_SET_ID").value
domain__field_length =data.fields("RDB$FIELD_LENGTH").value
domain__char_length =data.fields("RDB$CHARACTER_LENGTH").value
set domain__cset=nothing
'-----------
dim valid_cset_id
dim valid_field_length
dim valid_char_length
valid_cset_id =true
valid_field_length =true
valid_char_length =true
'------------------------------- Check NOT NULL
if(IsNull(domain__cset_id))then
valid_cset_id=false
valid_char_length=false
process_error check_domain_data__varying, "Column charset not defined"
end if
'-----------
if(IsNull(domain__field_length))then
valid_field_length=false
process_error check_domain_data__varying, "Length in bytes not defined"
end if
'-----------
if(IsNull(domain__char_length))then
valid_char_length=false
if(not domain__is_system)then
process_error check_domain_data__varying, "Length in chars not defined"
end if
end if
'------------------------------- Check charsetID
if(valid_cset_id)then
if(ctx.db_csets_by_id.Exists(domain__cset_id))then
set domain__cset=ctx.db_csets_by_id.Item(domain__cset_id)
else
valid_cset_id=false
process_error check_domain_data__varying, "Unknown charsetID: "&cstr_sn(domain__cset_id)
end if
end if 'valid_cset_id
'-------------------------------- Check char length
if(valid_char_length and valid_cset_id and valid_field_length)then
if((domain__char_length*domain__cset.bytes_per_char)<>domain__field_length)then
valid_char_length=false
msg="Wrong char count: "&cstr_sn(domain__char_length)&". "& _
"BytesPerChar: "&cstr_sn(domain__cset.bytes_per_char)&". "& _
"FieldLength: "&cstr_sn(domain__field_length)
process_error check_domain_data__varying, msg
end if
end if 'valid_char_length and valid_cset_id
'-------------------------------- Create correction SQL
dim comment
dim old_value
dim new_value
dim sql
dim sql_is_valid
'-------------------------------- SQL FOR RDB$FIELD_LENGTH
if(not valid_field_length)then
old_value=domain__field_length
sql_is_valid=valid_char_length and valid_cset_id
if(sql_is_valid)then
new_value=domain__char_length*domain__cset.bytes_per_char
else
new_value=c_sql__unk_value
end if
sql=data.sql_update_builder.gen(domain__name, _
"RDB$FIELD_LENGTH", _
old_value, _
new_value)
'----
comment="VARCHAR DOMAIN USED AT "&data.data_location
'----
call ctx.reg_correct_sql(sql_is_valid,sql,comment)
end if 'not valid_field_length
'-------------------------------- SQL FOR RDB$CHARACTER_LENGTH
if((not valid_char_length) and (not domain__is_system) and valid_cset_id)then
old_value=domain__char_length
if(not valid_field_length)then
sql_is_valid=false
else
sql_is_valid=((domain__field_length mod domain__cset.bytes_per_char)=0)
end if
if(sql_is_valid)then
new_value=domain__field_length / domain__cset.bytes_per_char
else
new_value=c_sql__unk_value
end if
sql=data.sql_update_builder.gen(domain__name, _
"RDB$CHARACTER_LENGTH", _
old_value, _
new_value)
comment="VARCHAR DOMAIN USED AT "&data.data_location
if(valid_cset_id)then
comment=comment&vbCrLf
comment=comment&"CSET_NAME : ["&domain__cset.name&"]"&vbCrLf
comment=comment&"CSET_ID : ["&domain__cset.id&"]"&vbCrLf
comment=comment&"BYTES_PER_CHAR : ["&domain__cset.bytes_per_char&"]"
end if
if(valid_field_length)then
comment=comment&vbCrLf
comment=comment&"FIELD_LENGTH : ["&domain__field_length&"]"&vbCrLf
end if
comment=comment&vbCrLf
comment=comment&"CURRENT CHAR_LENGTH: ["&cstr_sn(domain__char_length)&"]"
'----
call ctx.reg_correct_sql(sql_is_valid,sql,comment)
end if' not valid_char_length
'-------------------------------- SQL FOR RDB$CHARACTER_SET_ID
if(not valid_cset_id)then
old_value=domain__cset_id
new_value=c_sql__unk_value
sql=data.sql_update_builder.gen(domain__name, _
"RDB$CHARACTER_SET_ID", _
old_value, _
new_value)
sql_is_valid=false
comment="VARCHAR DOMAIN USED AT "&data.data_location
'----
call ctx.reg_correct_sql(sql_is_valid,sql,comment)
end if 'not valid_cset_id
end function 'check_domain_data__varying
'----------------------------------------------------------
private function get_nn(rs,field_index)
get_nn=rs(field_index).value
if(IsNull(get_nn))then
dim msg
msg="Field ["&rs(field_index).name&"] has NULL value"
call err.raise(-1,,msg)
end if
end function 'get_nn
'----------------------------------------------------------
private function get_value_or_default(rs,field_index,default_value)
get_value_or_default=rs(field_index).value
if(IsNull(get_value_or_default))then
get_value_or_default=default_value
end if
end function 'get_nn
'----------------------------------------------------------
class tag_intend
private m_prev_intend
private sub class_initialize()
m_prev_intend=g_intend
end sub 'class_inialize
private sub class_terminate()
g_intend=m_prev_intend
end sub 'class_terminate
end class 'tag_intend
'----------------------------------------------------------
private function add_intend(delta)
set add_intend=new tag_intend
call add(g_intend,delta)
end function 'add_intend
'----------------------------------------------------------
private sub process_error(byref err_count,msg)
call add(err_count,1)
print_error msg
end sub 'process_error
'----------------------------------------------------------
private sub print_error(msg)
print "ERROR: "&msg
end sub 'print_error
'----------------------------------------------------------
private sub print(msg)
out_text string(g_intend," ")&msg
end sub 'print
'----------------------------------------------------------
private sub out_text(msg)
wscript.echo msg
if(not(g_file_log is nothing))then
call g_file_log.WriteLine(msg)
end if
end sub 'out_text
'----------------------------------------------------------
private function cstr_sn(x)
if(IsNull(x))then
cstr_sn="#NULL"
elseif(IsEmpty(x))then
cstr_sn="#EMPTY"
else
cstr_sn=cstr(x)
end if
end function 'cstr_sn
'----------------------------------------------------------
private function inc(byref x)
inc=add(x,1)
end function 'inc
'----------------------------------------------------------
private function add(byref x,byval delta)
x=x+delta
add=x
end function 'add
'----------------------------------------------------------
private function sql__pack_name(name)
dim s
s="'"
dim i
for i=1 to len(name)
if(mid(name,i,1)="'")then
s=s&"'"
end if
s=s&mid(name,i,1)
next 'i
s=s&"'"
sql__pack_name=s
end function 'sql__pack_name
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'class tag_correct_sql
class tag_correct_sql
public sql_is_valid
public sql
public comment
end class 'tag_correct_sql
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'class tag_context
class tag_context
private m_cn
private m_db_csets_by_id
private m_processed__domains
private m_correct_sql
'----------------------------------------------
private sub class_initialize()
set m_cn=nothing
set m_db_csets_by_id=nothing
set m_processed__domains=nothing
set m_correct_sql=nothing
end sub 'class_initialize
'----------------------------------------------
public sub set_cn(cn)
set m_cn=cn
end sub 'set_cn
'----------------------------------------------
public sub set_db_csets_by_id(db_csets_by_id)
set m_db_csets_by_id=db_csets_by_id
end sub 'set_db_csets_by_id
'----------------------------------------------
public property get cn()
set cn=m_cn
end property 'get cn
'----------------------------------------------
public property get db_csets_by_id()
set db_csets_by_id=m_db_csets_by_id
end property 'get csets_by_id
'----------------------------------------------
public function mark_domain_as_processed(domain_name)
mark_domain_as_processed=false
if(m_processed__domains is nothing)then
set m_processed__domains=createobject("Scripting.Dictionary")
elseif(m_processed__domains.Exists(domain_name))then
exit function
end if
call m_processed__domains.add(domain_name,null)
mark_domain_as_processed=true
end function 'mark_domain_as_processed
'----------------------------------------------
public sub reg_correct_sql(sql_is_valid,sql,comment)
if(m_correct_sql is nothing)then
set m_correct_sql=createobject("LCPI.IBP.Samples.Vector.1")
end if
dim x
set x=new tag_correct_sql
x.sql_is_valid =sql_is_valid
x.sql =sql
x.comment =comment
call m_correct_sql.PushBack(x)
end sub 'reg_correct_sql
'----------------------------------------------
public property get has_correct_sql
has_correct_sql=false
if(m_correct_sql is nothing)then
exit property
end if
if(m_correct_sql.IsEmpty())then
exit property
end if
has_correct_sql=true
end property 'get has_correct_sql
'----------------------------------------------
public sub write_correct_sql_to_file(file)
if(not me.has_correct_sql)then
exit sub
end if
dim n
n=0
dim data
dim i
for i=0 to m_correct_sql.Count-1
n=n+1
set data=m_correct_sql(i)
call file.WriteLine _
("/*"&n&" --------------------------------- */")
call file.WriteLine _
("/*"&vbCrLf&data.comment&vbCrLf&"*/")
call file.WriteLine _
("")
call file.WriteLine _
(data.sql)
next 'i
call file.WriteLine _
("")
call file.WriteLine _
("/* --------------------------------- */")
call file.WriteLine _
("COMMIT;")
call file.WriteLine _
("/**/")
end sub 'write_correct_sql_to_file
end class 'tag_context
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class tag_sql_builder__update_domain_of_relation_fields
public relation_name
public field_name
public function gen(domain_name, _
domain_prop_name, _
domain_prop_old_value, _
domain_prop_new_value)
dim s
s="UPDATE RDB$FIELDS"&vbCrLf& _
"SET "&domain_prop_name&"="
if(IsNull(domain_prop_new_value))then
s=s&"NULL"
else
s=s&cstr(domain_prop_new_value)
end if
s=s&vbCrLf& _
"WHERE RDB$FIELD_NAME="&vbCrLf& _
" (SELECT RDB$FIELD_SOURCE"&vbCrLf& _
" FROM RDB$RELATION_FIELDS"&vbCrLf& _
" WHERE RDB$RELATION_NAME="&sql__pack_name(relation_name)&" AND"&vbCrLf& _
" RDB$FIELD_NAME="&sql__pack_name(field_name)&") AND"&vbCrLf& _
" "&domain_prop_name
if(IsNull(domain_prop_old_value))then
s=s&" IS NULL"
else
s=s&"="&cstr(domain_prop_old_value)
end if
s=s&";"
gen=s
end function 'gen
end class 'tag_sql_builder__update_domain_of_relation_fields
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
На выходе будет сформирован, к примеру, вот такой файл с исправлениями:
/*1 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[PROFILE].[CREATEBY]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [20]
CURRENT CHAR_LENGTH: [10]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=20
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='PROFILE' AND
RDB$FIELD_NAME='CREATEBY') AND
RDB$CHARACTER_LENGTH=10;
/*2 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[PAYMENT].[CALCFIXEDCCNO]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [35]
CURRENT CHAR_LENGTH: [0]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=35
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='PAYMENT' AND
RDB$FIELD_NAME='CALCFIXEDCCNO') AND
RDB$CHARACTER_LENGTH=0;
/*3 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[INVOICE].[REMARKS]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [4000]
CURRENT CHAR_LENGTH: [512]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=4000
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='INVOICE' AND
RDB$FIELD_NAME='REMARKS') AND
RDB$CHARACTER_LENGTH=512;
/*4 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[INVOICE].[CALCINVOICENUMBER]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [11]
CURRENT CHAR_LENGTH: [0]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=11
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='INVOICE' AND
RDB$FIELD_NAME='CALCINVOICENUMBER') AND
RDB$CHARACTER_LENGTH=0;
/*5 --------------------------------- */
/*
CHAR DOMAIN USED AT {TABLE}[BOOKING].[CALCTRIMVENDORREMARKS]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [253]
CURRENT CHAR_LENGTH: [0]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=253
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='BOOKING' AND
RDB$FIELD_NAME='CALCTRIMVENDORREMARKS') AND
RDB$CHARACTER_LENGTH=0;
/*6 --------------------------------- */
/*
CHAR DOMAIN USED AT {TABLE}[BOOKING].[CALCTRIMCLIENTREMARKS]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [253]
CURRENT CHAR_LENGTH: [0]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=253
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='BOOKING' AND
RDB$FIELD_NAME='CALCTRIMCLIENTREMARKS') AND
RDB$CHARACTER_LENGTH=0;
/*7 --------------------------------- */
/*
CHAR DOMAIN USED AT {TABLE}[BOOKING].[CALCTICKETCONFIRMNO]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [253]
CURRENT CHAR_LENGTH: [0]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=253
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='BOOKING' AND
RDB$FIELD_NAME='CALCTICKETCONFIRMNO') AND
RDB$CHARACTER_LENGTH=0;
/*8 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {VIEW}[PROFILEVIEW].[FIRSTANDLAST]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [81]
CURRENT CHAR_LENGTH: [#NULL]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=81
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='PROFILEVIEW' AND
RDB$FIELD_NAME='FIRSTANDLAST') AND
RDB$CHARACTER_LENGTH IS NULL;
/*9 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {VIEW}[PROFILEVIEW].[LASTANDFIRST]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [81]
CURRENT CHAR_LENGTH: [#NULL]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=81
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='PROFILEVIEW' AND
RDB$FIELD_NAME='LASTANDFIRST') AND
RDB$CHARACTER_LENGTH IS NULL;
/*10 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {VIEW}[PROFILEVIEW].[FIRSTANDLASTUPPER]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [81]
CURRENT CHAR_LENGTH: [#NULL]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=81
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='PROFILEVIEW' AND
RDB$FIELD_NAME='FIRSTANDLASTUPPER') AND
RDB$CHARACTER_LENGTH IS NULL;
/*11 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {VIEW}[PROFILEVIEW].[LASTANDFIRSTUPPER]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [81]
CURRENT CHAR_LENGTH: [#NULL]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=81
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='PROFILEVIEW' AND
RDB$FIELD_NAME='LASTANDFIRSTUPPER') AND
RDB$CHARACTER_LENGTH IS NULL;
/*12 --------------------------------- */
/*
CHAR DOMAIN USED AT {VIEW}[BOOKINGVIEW].[CLIENTREMARKS]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [253]
CURRENT CHAR_LENGTH: [#NULL]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=253
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='BOOKINGVIEW' AND
RDB$FIELD_NAME='CLIENTREMARKS') AND
RDB$CHARACTER_LENGTH IS NULL;
/*13 --------------------------------- */
/*
CHAR DOMAIN USED AT {VIEW}[BOOKINGVIEW].[VENDORREMARKS]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [253]
CURRENT CHAR_LENGTH: [#NULL]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=253
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='BOOKINGVIEW' AND
RDB$FIELD_NAME='VENDORREMARKS') AND
RDB$CHARACTER_LENGTH IS NULL;
/*14 --------------------------------- */
/*
CHAR DOMAIN USED AT {VIEW}[BOOKINGVIEW].[TICKETCONFIRMNO]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [253]
CURRENT CHAR_LENGTH: [#NULL]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=253
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='BOOKINGVIEW' AND
RDB$FIELD_NAME='TICKETCONFIRMNO') AND
RDB$CHARACTER_LENGTH IS NULL;
/*15 --------------------------------- */
/*
CHAR DOMAIN USED AT {VIEW}[BOOKINGPSGRVIEW].[PASSENGERDEPTUPPER]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [254]
CURRENT CHAR_LENGTH: [#NULL]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=254
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='BOOKINGPSGRVIEW' AND
RDB$FIELD_NAME='PASSENGERDEPTUPPER') AND
RDB$CHARACTER_LENGTH IS NULL;
/*16 --------------------------------- */
/*
CHAR DOMAIN USED AT {VIEW}[BOOKINGPSGRVIEW].[PASSENGERDEPT]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [254]
CURRENT CHAR_LENGTH: [#NULL]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=254
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='BOOKINGPSGRVIEW' AND
RDB$FIELD_NAME='PASSENGERDEPT') AND
RDB$CHARACTER_LENGTH IS NULL;
/*17 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[PNRBRANCHSETTINGS].[PSEUDOCITY]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [8]
CURRENT CHAR_LENGTH: [3]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=8
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='PNRBRANCHSETTINGS' AND
RDB$FIELD_NAME='PSEUDOCITY') AND
RDB$CHARACTER_LENGTH=3;
/*18 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[ACTIVITY].[USERNAME]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [20]
CURRENT CHAR_LENGTH: [15]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=20
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='ACTIVITY' AND
RDB$FIELD_NAME='USERNAME') AND
RDB$CHARACTER_LENGTH=15;
/*19 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[RESCARDRESERVATION].[SOURCEOFBOOKING]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [25]
CURRENT CHAR_LENGTH: [20]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=25
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='RESCARDRESERVATION' AND
RDB$FIELD_NAME='SOURCEOFBOOKING') AND
RDB$CHARACTER_LENGTH=20;
/*20 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[RESCARD].[GROUPNAME]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [128]
CURRENT CHAR_LENGTH: [20]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=128
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='RESCARD' AND
RDB$FIELD_NAME='GROUPNAME') AND
RDB$CHARACTER_LENGTH=20;
/*21 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[RESCARDPROVIDER].[DINING]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [30]
CURRENT CHAR_LENGTH: [15]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=30
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='RESCARDPROVIDER' AND
RDB$FIELD_NAME='DINING') AND
RDB$CHARACTER_LENGTH=15;
/*22 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[RESCARDPROVIDER].[AIRCRAFTLOCATOR]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [12]
CURRENT CHAR_LENGTH: [10]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=12
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='RESCARDPROVIDER' AND
RDB$FIELD_NAME='AIRCRAFTLOCATOR') AND
RDB$CHARACTER_LENGTH=10;
/*23 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[LIVECONNECTPROVIDER].[PROVIDERNAME]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [60]
CURRENT CHAR_LENGTH: [30]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=60
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='LIVECONNECTPROVIDER' AND
RDB$FIELD_NAME='PROVIDERNAME') AND
RDB$CHARACTER_LENGTH=30;
/*24 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[MARKETINGCODE].[CODEVALUE]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [80]
CURRENT CHAR_LENGTH: [20]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=80
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='MARKETINGCODE' AND
RDB$FIELD_NAME='CODEVALUE') AND
RDB$CHARACTER_LENGTH=20;
/*25 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[VENDORLIVECONNECT].[VENDORCODE]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [128]
CURRENT CHAR_LENGTH: [20]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=128
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='VENDORLIVECONNECT' AND
RDB$FIELD_NAME='VENDORCODE') AND
RDB$CHARACTER_LENGTH=20;
/*26 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[USERLIVECONNECT].[LCPASSWORD]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [80]
CURRENT CHAR_LENGTH: [20]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=80
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='USERLIVECONNECT' AND
RDB$FIELD_NAME='LCPASSWORD') AND
RDB$CHARACTER_LENGTH=20;
/*27 --------------------------------- */
/*
VARCHAR DOMAIN USED AT {TABLE}[USERLIVECONNECT].[USERNAME]
CSET_NAME : [NONE]
CSET_ID : [0]
BYTES_PER_CHAR : [1]
FIELD_LENGTH : [80]
CURRENT CHAR_LENGTH: [20]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_LENGTH=80
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME='USERLIVECONNECT' AND
RDB$FIELD_NAME='USERNAME') AND
RDB$CHARACTER_LENGTH=20;
/* --------------------------------- */
COMMIT;
/**/
Kovalenko on 27 сентября, 2011
Обновление скрипта.
1. Исправил багу, которая обнаружилась в процессе полевого испытания.
2. Добавил константу «c_db_client», которая упрощает указание клиентской библиотеки.
Пример запроса, который будет сформирован, если обнаружится текстовая колонка без кодовой страницы (это болезнь VIEW баз данных Interbase).
/*
VARCHAR DOMAIN USED AT {VIEW}[PNM_BYDESCR_VIEW].[DESCRIPTION]
*/
UPDATE RDB$FIELDS
SET RDB$CHARACTER_SET_ID=??>
WHERE RDB$FIELD_NAME=
(SELECT RDB$FIELD_SOURCE
FROM RDB$RELATION_FIELDS
WHERE RDB$RELATION_NAME=’PNM_BYDESCR_VIEW’ AND
RDB$FIELD_NAME=’DESCRIPTION’) AND
RDB$CHARACTER_SET_ID IS NULL;