Introdução
Existem diferenças entre DB PROGRESS e DB SQL Server
O desenvolvedor deve ter estas diferenças em mente
quando está construindo seus programas.
É preciso saber para qual(is) Data Source(s) o programa está
sendo construído.
Arquitetura DataServer
Progress Application
Progress Enterprise DataServer for SQL Server
ODBC Driver Manager
ODBC Driver
ODBC Driver
DATA SOURCE
DATA Source Manager
DATA SOURCE
Funcionamento do DataServer
SQL SERVER
O usuário executa um aplicativo Progress
O DataServer faz a tradução o comando Progress para
SQL
ODBC API
O Data Source recebe a sentença SQL
O Data Source Manager manda para o SQL Server
e retorna o resultado
O progress mostra o resultado.
Funcionamento do DataServer
SQL SERVER
FOR EACH customer: Display name. End. SELECT name FROM customer. ODBC API SELECT name FROM customer. ‘João’ ‘Maria’ ‘José’ Nome ---‘João’ ‘Maria’ ‘José’
Schema Holder
Progress Schema Holder ---Cust-num – Integer Name – Character Max_credit - Decimal DATA SOURCE DATA DEFINITIONS ---Cust_num – Int Name – Char Max_credit - decimal• Schema Holder tem informações sobre os objetos do Data Sources MSS
• Progress acessa apenas na compilação e no inicio do Run-Time (Schema Caching)
Configuração Básica
Local DataServer
PROGRESS CLIENT
DATASERVER
ODBC DRIVER
DATA-SOURCE CLIENT SOFTWARE SCHEMA
HOLDER
DATA
SOURCE CLIENT
SCHEMA HOLDER PROGRESS CLIENT DATASERVER ODBC DRIVER DATA-SOURCE SOFTWARE Progress Client CLIENT SQL SERVER
SERVER Progress Enterprise
Dataserver
Configuração Básica
Remote DataServer
Objetos PROGRESS e Objetos SQL Server
O dataserver suporta sequências através de Stored Procedures nativas
Sequences Default Initial Value Foreign Key Nonunique Index Primary Key Unique Index Index Index Row Record Column Field Table Table/File SQL SERVER PROGRESS
Considerações Gerais
Cada tipo suportado pelo Dataserver tem pelo menos um equivalente no Progress
Tinyint
Logical
Integer
Integer
Decimal
Decimal
Datetime
Date
Varchar
Character
SQL SERVER PROGRESS RawText
Tipos de Dados
Número máximo de atributos por tabela 1024
Número máximo de índices por tabela 249
Número máximo de atributos num índice 16
Soma colunas que compõem o índice 900 bytes
Tamanho máximo para campos Caracter x(8000)
Campos Decimal 28 dígitos
Campos Integer 9 dígitos
Campos Datetime de 01/01/1753 a 31/12/9999
Além das validações existentes para Oracle:
Homologação de dicionário será realizada pelo DWB-DDD através da opção ADF -> Magnus 97 -> Auditoria DataServer.
Valida o tamanho dos índices verificando a possibilidade de ultrapassar o tamanho máximo de 400 bytes para índices
únicos e 396 para os não únicos.
Reporta a existência de campos Date com Initial < 01/01/1800 caso tal opção esteja selecionada.
Verifica a possibilidade de estouro de registro maior que 8k(menos formatos >= x(8000).
Quando da migração, o protomss cria automaticamente dois campos adicionais nas tabelas(progress_recid e
progress_recid_indent) com o objetivo de manter compatibilidade com as funções RECID e ROWID.
Campos array(extent) serão convertidos com a convenção campo##1 até campo##n onde n é o número de extents do campo.
Para cada seqüência será criada uma tabela no SQL com seus respectivos valores e uma stored procedure para emular o comportamento do Progress.
Todos os campos a partir de x(8000) serão transformados em campos text no SQL. Os menores que este formato serão sempre varchar. Os campos tipo RAW também serão
convertidos para text.
Alteração Templates/Comportamento Programas
Desabilitação do botão de última ocorrência tanto para Client-Server como para WEB.
Alteração das includes de dbtype para MSS
Validação para programas de tela dos valores para Campos Date(> 01/01/1800) Client-Server e WEB
Unknown Values (?)
São suportados pelo Dataserver
Unknown Values e Brancos não são a mesma coisa
Os Unknown Values são armazenados como Nulls (?) e strings vazias são armazenadas como 1 (um) espaço “ ” em
Unknown Values (?)
Cláusulas do tipo >= ? e <= ? devem ser substituídas por > ? or = ? e < ? or = ? para campos do tipo date, character, integer e decimal.
Cláusulas do tipo > ? devem ser substituídas por <> ? para campos do tipo date.
Quando usamos unknown values em uma cláusula WHERE, apenas se pode satisfazer a condição com operadores = (equal) ou <> (not equal).
Unknown Values (?) - Exemplos
FOR EACH Customer NO-LOCK WHERE Address <> "": ...
END.
PROGRESS
FOR EACH Customer NO-LOCK WHERE Address <> "": ...
END.
SQL SERVER
Cust-Num Name Address
1 Lift Line Skiing 276 North Street 2 Urpon Frisbee
3 Hoops Croquet Co. ?
4 Go Fishing Ltd ?
5 Match Point Tennis
Cust-Num 1 3 4 Cust-Num 1
FOR EACH Customer NO-LOCK WHERE Address <> "" OR
Address = ?: ...
Cust-Num Name Address
1 Lift Line Skiing 276 North Street 2 Urpon Frisbee
3 Hoops Croquet Co. ?
4 Go Fishing Ltd ?
5 Match Point Tennis
FOR EACH Customer NO-LOCK WHERE Address <> ?: ... END. PROGRESS Cust-Num 1 2 5
FOR EACH Customer NO-LOCK WHERE Address <> ?: ...
END.
SQL SERVER
Cust-Num Name Address
1 Lift Line Skiing 276 North Street 2 Urpon Frisbee
3 Hoops Croquet Co. ?
4 Go Fishing Ltd ?
5 Match Point Tennis
FOR EACH Customer NO-LOCK WHERE Address >= ?: ... END. PROGRESS Cust-Num 3 4
FOR EACH Customer NO-LOCK WHERE Address >= ?: ... END. SQL SERVER Não encontra os registros
FOR EACH Customer NO-LOCK WHERE Address > ? OR
Address = ?: ...
END.
FOR EACH customer
WHERE customer.address = "“: DISPLAY customer.cust-num. END.
PROGRESS e SQL SERVER
FOR EACH customer
WHERE customer.address = “ “: DISPLAY customer.cust-num. END.
Cust-Num Name Address
1 Lift Line Skiing 276 North Street 2 Urpon Frisbee
3 Hoops Croquet Co. ?
4 Go Fishing Ltd ?
5 Match Point Tennis 20 Bicep Bridge Rd
Cust-Num
2
Cust-Num Name Address
1 Lift Line Skiing 276 North Street 2 Urpon Frisbee
3 Hoops Croquet Co. ?
4 Go Fishing Ltd ?
5 Match Point Tennis 20 Bicep Bridge Rd
FOR EACH customer
WHERE customer.address BEGINS "“: DISPLAY customer.cust-num address. END. PROGRESS e SQL SERVER Cust-Num Address 1 276 North Street 2 5 20 Bicep Bridge Rd
FOR EACH customer
WHERE customer.address BEGINS “ “: DISPLAY customer.cust-num address. END.
Cust-Num Address
1 276 North Street
Embora “” e “ ” tenham o mesmo comportamento em cláusulas WHERE, possuem diferentes resultados quando usados junto com a função BEGINS
Campos do tipo character possuem tamanho fixo
CREATE Customer. ASSIGN Cust-Num = 1
Name = "Lift " + FILL("*", 50).
PROGRESS
CREATE Customer. ASSIGN Cust-Num = 1
Name = "Lift " + FILL("*", 50).
SQL SERVER
CREATE Customer. ASSIGN Cust-Num = 1 Name = SUBSTRING("Lift " + FILL("*", 50), 1, 20).Rowid
Fornece um único registro identificador que é compatível com Progress e SQL Server
A Progress recomenda que sejam trocados os RECID por ROWID nas aplicações existentes, mas a compatibilidade com RECID funciona sem problemas.
Field Lists
Deve ser incluída a opção NO-LOCK em comandos OPEN QUERY e FOR EACH que utilizam field lists
Find
Suporta os comandos FIND FIRST, CURRENT, LAST, PREV e NEXT
Compile
Se for alterado o nome do schema holder após o programa ter sido compilado, deve ser recompilado contra o schema holder renomeado
Não há necessidade de conectar o banco SQL Server para compilar o programa. O schema holder contém todas as informações que o compilador exige
Begins/Matches
Evitar utilizar pois resulta em baixa performance Se possível, utilizar claúsulas normais(=,>,<,<>)
Word-Index
Não é suportado pelo Dataserver
Contains
Está relacionado a word-index. Não é suportado pelo Dataserver
Count-Of
Não é suportado pelo Dataserver
Raw-transfer
Converter o campo raw para caracter
Current-Value
Pode ser utilizado a partir da 9.1C sem problemas.
Open Query
Registro criados após a abertura da query não estão disponíveis, deve-se reabrí-la
Session:Time-Source
Deve retornar o local do schema holder
Fields
Somente pode ser utilizado com No-Lock
Where
Quando utilizado com campos text do SQL
SetUserID
Poderá ser utilizado apontando para o Schema Holder.
Existe perda de performance ao utilizar a função MATCHES
Contains
FOR EACH Customer WHERE Name CONTAINS "Bug": DISPLAY Cust-Num Name.
END.
PROGRESS
Cust-Num Name
29 Bug in a Rug-by
FOR EACH Customer WHERE Name CONTAINS "Bug": DISPLAY Cust-Num Name.
END.
SQL SERVER
FOR EACH Customer WHERE Name MATCHES "Bug*": DISPLAY Cust-Num Name.
END.
Session:Time-Source SESSION:TIME-SOURCE = ldbname('sports'). DISP SESSION:TIME-SOURCE. PROGRESS c:\tmp\sports SESSION:TIME-SOURCE = ldbname('sports'). DISP SESSION:TIME-SOURCE. SQL SERVER SESSION:TIME-SOURCE = ldbname(‘shsports'). DISP SESSION:TIME-SOURCE.
Comandos 4GL - Exemplos
A criação do registro tem tratamento diferente para Progress x SQL Server
Pode-se forçar a gravação do registro através dos comandos: Validate e Release (porém disparam a execução das Triggers de Write do Dicionário)
Funções Rowid/Recid forçam a criação do registro, gravando os campos mandatory (estas funções não disparam a execução das Triggers de Write)
DO TRANSACTION: CREATE customer. name = “Smith”. cust-Num = 10. address = “1 Main St”. END. PROGRESS
Progress não cria o registro no CREATE. É criado quando a informação do índice é fornecida. DO TRANSACTION: CREATE customer. name = “Smith”. cust-Num = 10. address = “1 Main St”. END. SQL SERVER
O registro é criado após executar o END.
DEFINE BUFFER bfCust FOR customer.
CREATE customer.
ASSIGN cust-num = 111.
FIND bfCust WHERE bfCust.cust-Num = 111. DISPLAY bfCust.cust-num.
PROGRESS
DEFINE BUFFER bfCust FOR customer.
CREATE customer.
ASSIGN cust-num = 111.
FIND bfCust WHERE bfCust.cust-num = 111. DISPLAY bfCust.cust-num.
SQL SERVER
Cust-Num 111
DEFINE BUFFER bfCust FOR customer.
CREATE customer.
ASSIGN cust-num = 111.
VALIDATE customer. /* ou RELEASE */
FIND bfCust WHERE bfCust.cust-num = 111. DISPLAY bfCust.cust-num.
Se for setado valor default quando estiver criando o registro, deve ser alterado antes de ser criado o outro (se o campo fizer parte do índice único), pois senão irá causar um erro deduplicidade de chave
Atualizações de registros são tratadas de forma similar a
criação dos registros. A atualização é feita no final do escopo ou no final da transação
Share-Lock
Não utilizar
O dataserver ignora a opção share-lock, será necessário verificar o código e optar por NO-LOCK ou EXCLUSIVE-LOCK Exclusive-Lock e No-Lock
O comportamento destes é o mesmo do DB Progress Deve-se utilizar optimistic lock
DO TRANSACTION:
FIND Customer WHERE Cust-Num = 11 NO-LOCK. DISPLAY Name Credit-Limit Balance Sales-Rep. PROMPT-FOR Name Credit-Limit Balance Sales-Rep. FIND CURRENT Customer EXCLUSIVE-LOCK.
ASSIGN Name Credit-Limit Balance Sales-Rep. END.
rep-blk: repeat:
prompt-for customer.cust-num.
find customer using cust-num no-error. if available customer then
update customer.cust-num name customer.state. do-blk:
do on error undo do-blk, retry do-blk:
find state where state.state = customer.state. display state.
set state. end.
end.
PROGRESS SQL SERVER
Tratamento de Erros
Os comandos FOR EACH e FIND podem retornar os registros em uma ordem imprevisível
Quando a ordem dos registros é importante deve-se utilizar as opções By ou Use-Index, porém podem reduzir a performance
Ordem dos Registros
Query Tuning
A estrutura de uma query determina se o acesso a base de dados está sendo feito de forma eficiente. O padrão para elevar a performance é usar um critério de seleção para refinar o acesso ao dado, mas podemos favorecer a execução de uma query através de expressão específica Progress QUERY-TUNING.
Exemplos
FOR EACH <tabela> QUERY-TUNING <query-tuning-option) OPEN QUERY <query> QUERY-TUNING <query-tuning-option)
Aumento de Performance
Opções QUERY-TUNING
array-message / no-array-message cache-size
debug extended / debug sql / no-debug join-by-sqldb / no-join-by-sqldb
lookahead / no-lookahead
separate-conection / no-separate-conection
Aumento de Performance
Joins
Para determinar se uma join é possível, o dataserver avalia se os seguintes critérios são verdadeiros:
Todas as tabelas na join serem do mesmo banco lógico, isto é, estarem contidas no mesmo schema
Cada tabela ter um único registro identificador A query não incluir a opção USING
A query não incluir expressões que contenham BY ou campos array
A join não exceder 10 níveis
Aumento de Performance
Queries que processam grande volume de registros, executam melhor se usarmos no-lock, um grande tamanho de cache e field list pequeno
Utilizar comandos FOR EACH, GET e OPEN QUERY de preferência, ao invés do comando FIND, quando a performance estiver mais lenta
Utilizar FOR FIRST ao invés de FIND FIRST. Utilizar FIND LAST ao invés de GET LAST(Full Table Scan)
Utilizar field lists
Utilizar as opções de QUERY-TUNING
Utilizar sempre NO-LOCK quando possível
Não solicitar uma ordenação especial dos registros com cláusulas que utilizam USE-INDEX ou BY, a menos que a aplicação exigir. Permitir ao dataserver determinar o índice mais eficiente para processar a query
Se for utilizar a cláusula BY para classificar uma grande quantidade de registros, garanta a existência de um índice correspondente para fazer uma classificação eficiente
Quando testar a existência de um registro, utilizar a função CAN-FIND FIRST
Evite usar a função RECID. Ao invés disto, use a função ROWID
Aumento de Performance – Dicas Gerais
Problema
Only binary SQL fields can be updated with RAW data.(6187) Campos com “-” após campo raw são criados com “_” no schema
Causa
Existência campos do tipo raw no dicionário
Ação
Mudar o tipo de dado para CHAR
Problemas Conversão p/ SQL Server
Problema
O servidor de banco de dados especificado não suporta esta função.(4634)
Causa
assign session:time-source = ldbname(‘mguni’).
Ação
O SQL não suporta a função time-source. Portanto, substituir o nome do banco mguni pelo nome do schema holder shems2uni.
Problemas Execução com SQL Server
Problema
Database mguni has type MSS (869)
But connection to type Progress was requested.
Causa
&if "{&mguni_dbtype}" = "progress" &then <executa instruções para progress> &else
<executa instruções para outros tipos de bancos>
Ação
Alterar include i_dbtype.i para
&GLOBAL-DEFINE <nome-logico-banco>_dbtype MSS
Problemas Execução com SQL Server
Problema
Voce tentou comparar ou atualizar um campo caracter com um valor maior do que o tamanho maximo. (6182)
Causa
def var v_cod_modul_dtsul_fim as character format "x(3)" initial "zzzzzzzz" label "Modulo Final" column-label "Módulo“. open query qr_sea_modul_dtsul FOR each modul_dtsul no-lock
where modul_dtsul.cod_modul_dtsul >= v_cod_modul_dtsul_ini and modul_dtsul.cod_modul_dtsul <= v_cod_modul_dtsul_fim
by modul_dtsul.cod_modul_dtsul.
Pois o cod_modul_dtsul tem tamanho x(3) e está comparando com a variável que apesar de ter o mesmo formato do campo, tem
valor inicial “zzzzzzzz” – x(8).
Ação
Identificado como bug, está corrigido no Patch 9.1D05. Para gravação continua a mensagem, como ocorre no Oracle
Problema
GPF no momento de executar um OPEN QUERY ou FOR EACH com mais de três níveis quando utilizada a função ROWID
Causa
def var rvar as rowid no-undo.
for each customer, each order of customer , each order-line of order where rowid(order-line) <> rvar:
disp order. end.
Ação
Bug no DataServer Progress. Liberado patch de correção 9.1D03
Problemas Execução com SQL Server
Problema
Registro Mostrado no For Each após criado em uma transação gerada dentro deste Bloco, sendo que em Progress, todos os registros no For Each já são trazidos para o Buffer, não apresentando o
problema, e em SQL Server, como cada iteração deste comando gera um SELECT a ser executado no DataSource, estes registros são trazidos, apresentando diferenças no resultado de alguns
programas.
Causa
A não existência de Transação no For Each, para que o programa gere uma sub-transação desta transação maior no momento da criação do Registro.
Ação
Utilização da claúsula TRANSACTION no For Each ou criação desta através do comando DO.
Problema
Action Segment has exceeded its limit of 63488 bytes, in at line # 1611. (3307). A partir da versão 9.1C tem-se também a mensagem 9430, alertando para a utilização de mais de um action code no programa, o que o impossibilita de ser rodado em versões
anteriores.
Causa
Excesso de procedures internas, código de programa. A partir da 9.1C, existem quatro segmentos de action code para o main Block. O que minimiza o problema, mas ainda ocorrem problemas que serão necessários retrabalhos. Quando ocorre o estouro de mais de um action code, o Progress avisa mas compila o programa. Estes somente poderão ser rodados contra a versão >= 9.1C.
Ação
Mover código para novos programas
Problema
System error: Data/Time format error(6175)
Causa
Tentativa de gravar uma data inferior ao limite mínimo do SQL Server de 01/01/1753. Este problema ocorria também na
comparação de datas inferiores a este valor, mas a Progress
implementou o parâmetro -Dsrv ZPRGRS_MSS_DATE_RANGE,1, que realiza o tratamento da comparação de datas automaticamente pelo DataServer.
Ação
Realizar a validação para que estas Datas não sejam gravadas com valores menores que 01/01/1753.
Comentários Finais
Estas limitações em relação ao SQL Server estão descritas na técnica de programação “TECDES.04-Programação.doc”
As informações em relação aos pontos para migração de
dicionário estão em TEC.075 - Check List Inspeção Oracle-SQL Server.doc
ORACLE
Campos Recid
Atributos não mandatórios fazendo parte do índice
Tabelas com número de atributos maior que 1000