770 likes | 831 Views
Linguagens de Programação de Bases de Dados. João Correia Lopes FEUP/INESC http://www.fe.up.pt/~jlopes/teach/ jlopes@inescn.pt. Referências: 1. C. Delobel, C. Lécluse, P. Richard. Databases: From Relational to Object-Oriented Systems, International Thomson Publishing, London, UK, 1995
E N D
Linguagens de Programação de Bases de Dados João Correia Lopes FEUP/INESC http://www.fe.up.pt/~jlopes/teach/ jlopes@inescn.pt Referências: 1.C. Delobel, C. Lécluse, P. Richard. Databases: From Relational to Object-Oriented Systems, International Thomson Publishing, London, UK, 1995 2. L. Cardelli, P.Wegner. On Understanding types, data abstraction and Polymorphism. ACM Computing Surveys, 17(4):471-523, December, 1985 3. N. Paton, R. Cooper, H. Williams, P. Trinder. Database Programming Languages. Prentice Hall International, Series in Computer Science, 1996 v 1.1, Março, 1999
Índice • modelos de dados • sistemas de tipos • extensões ao modelo relacional • linguagens de programação de bases de dados • linguagens persistentes ortogonais • Napier88
Integração de Modelos de Dados e Sistemas de Tipos • os novos SGBDs devem possuir maior capacidade de modelização que os baseados no modelo relacional, e • estar melhor integrados com as linguagens de programação • modelos de dados • para suprir limitações do modelo relacional em termos de modelização (o fosso semântico) • através de um maior número de abstracções: classificação, generalização, … • são tradicionalmente usados nas bases de dados para descrever o modelo estático (dados) • normalmente são pouco adaptados à descrição do modelo dinâmico (computações) • sistemas de tipos • as linguagens de programação com sistemas de tipos mais complexos mapeiam com mais facilidade a informação do mundo real • através da introdução de tipos mais elaborados, polimorfismos, encapsulamento, .… • tradicionalmente usados nas linguagens de programação para descrever computações (complexas) • constituem o equivalente para as linguagens de programação ao esquema da base de dados • integração dos dois conceitos = linguagens de programação de bases de dados
Modelos de Dados • são usados na obtenção do modelo conceptual de sistemas de informação • metodologias centradas no uso de um modelo semântico por forma a obter uma descrição independente do ambiente e isenta de detalhes de implementação • tentam minorar a chamada “crise de software” [RAM 84] • os projectos são entregues muito depois do prazo • a qualidade é pobre • a manutenção é cara Estrutura Conceptual Estrutura Lógica modelo semântico base de dados gerida pelo SGBD modelo relacional modelo hierárquico modelo reticulado Estrutura Física
Abstracções Comuns a Vários Modelos de Dados • classes e entidades • uma classe é um conjunto de entidades com características comuns • uma entidade possui uma identidade imutável e independente de modificações eventuais • esta noção não existe no modelo relacional • é essencial para certas aplicações (e.g. CAD) • agregações • agrupar várias entidades numa entidade de nível superior (endereço = cidade x rua x no-policia) • associações • não criam uma entidade • ligam várias entidades • podem conter restrições à cardinalidade • atributos • relações bidireccionais entre duas classes de entidades • mono-valor (pessoa –> nome) ou multi-valor (pessoa –>> filhos) • agrupamento • constrói uma entidade a partir de um conjunto (finito) de entidades com uma dada estrutura • a sua identidade é determinada pela identidade dos componentes (e.g. Pessoal: Monumento –> Pessoa) • é diferente de uma classe porque esta não é uma entidade mas sim uma meta-primitiva • é diferente de um atributo multi-valor porque com um agrupamento pode referir-se explicitamente todo o conjunto e com um atributo só se pode referir a associação Pessoal Monumento Pessoa
Modelização Baseada em Construtores • a modelização enfatizando o uso de agregações, associações e agrupamentos para representar ligações entre entidades • o esquema pode ser visto como um conjunto de estruturas obtidas pela aplicação de construtores • tuplo: agregação, associação • conjunto: agrupamento • … nome Dirige nome N 1 Monumento Pessoa filho salário
Modelização Baseada em Atributos • a modelização enfatizando o uso de atributos para representar ligações entre entidades • atributos ligam classes de entidades • não há novas estruturas construídas como no caso anterior nome nome Dirigido filho Monumento Pessoa Dirige
Especialização e Generalização • na especialização uma classe é redefinida numa sub-classe • e.g. Empregado especialização de pessoa • a especialização pode ser explícita • indicada explicitamente na altura da criação • ou derivada • indicada através de um predicado • na generalização uma classe é definida como a união de várias classes • e.g. Monumento, Museu e Palácio • as várias classes podem ser mutuamente exclusivas • não existem entidades pertencentes à generalização (e.g. Monumento) na base de dados • o grafo de especialização/generalização constitui a hierarquia ISA ou hierarquia de herança nome nome Monumento idade Pessoa idade<33 Jovem Empregado Museu Palácio
Restrições de Integridade • para além das restrições de integridade estruturais (directamente nas primitivas do modelo) • restrições de integridade adicionais são usadas para enriquecer o poder expressivo dos modelos semânticos • restrições na chave (vide modelo relacional) são traduzidas por atributos mono-valor ou são desnecessárias no caso das entidades possuírem a sua própria identidade • atributos parciais podem ser usados no caso de serem opcionais • atributos totais, no caso de serem obrigatórios • restrições de cardinalidade podem ser especificadas para as associações de entidades Notas finais sobre modelos de dados: • exemplos de modelos semânticos • E/A, SDM, IFO, RM/T, DAPLEX, INFOLOG • os modelos de dados têm por objectivo representar os dados importantes para uma dada aplicação • A aproximação à modelização usando técnicas orientadas aos objectos (O-O) permite a implementação de numerosas características dos modelos semânticos e proporciona ainda a modelização do comportamento dos objectos
Sistemas de Tipos • o objectivo de uso dos tipos nas linguagens de programação é o de distinguir valores usados na execução de programas • o conceito de tipo é similar ao conceito de classe mas é usado noutro contexto e com objectivos distintos • o objectivo de um sistema de tipos é o de prevenir a ocorrência de erros durante a execução dos programas • illegal instruction fault • illegal memory reference • divisão por zero • desreferenciar NIL • o que é um tipo? • a gama de valores que uma variável de um programa pode tomar durante a execução do programa • exemplo: x é booleana not(x) tem significado • o sistema de tipos é o componente de uma linguagem tipada que tem em atenção os tipos das variáveis ou os tipos das expressões num programa
Tipagem • linguagem tipadas • podem ser atribuídos tipos ás variáveis • linguagens não tipadas • não colocam qualquer restrição à gama de valores que as variáveis podem tomar • não têm tipos, ou podemos dizer que possuem um tipo universal que contém todos os valores possíveis • exemplos: • cadeias de bits na memória do computador • o significado de uma zona de memória é determinado por uma interpretação do seu conteúdo • expressões do calculus lambda • tudo são funções; não podem ocorrer erros já que a única operação é a aplicação de funções • expressões S do LISP puro • o programa e os dados são expressões S • conjuntos na teoria dos conjuntos • temos elementos ou conjuntos de elementos • apontadores em Smalltalk
Linguagens Fortemente Tipadas • erros de execução podem ser: • interceptáveis (TRAPed) • obrigam o computador a parar • e.g. “divide by zero”, “illegal address”, “overflow” • não-interceptáveis (UNTRAPed) • e.g. aceder a um endereço ilegal • ir além dos limites de um array • saltar para um endereço errado e interpretar o conteúdo como sendo uma instrução • um programa é seguro se não causa erros não-interceptáveis • uma linguagem é segura se todos os fragmentos dos seus programas são seguros • linguagens tipadas garantem a segurança dos programas rejeitando todos os programas que sejam potencialmente inseguros • através de análise estática • ou através de verificações em tempo de execução (runtime) • note-se que linguagens não tipadas podem garantir a segurança através de verificações em tempo de execução • erros proibidos nas linguagens seguras incluem normalmente mais do que os erros chamados não-interceptáveis • uma linguagem é fortemente tipada se: • não ocorrem erros não-interceptáveis • nenhum dos erros proibidos pode ocorrer • os outros erros, interceptáveis, podem ocorrer e é da responsabilidade do programador evitá-los
Segurança versus Flexibilidade • C é uma linguagem segura? • PASCAL é uma linguagem suficientemente flexível? • em termos de segurança: • o C não é seguro • aritmética de apontadores • “casts” • a tendência é no sentido de maior segurança • C++ • Java • em termos de flexibilidade • em PASCAL uma função genérica que traduza maiúsculas em minúsculas em cadeias de caracteres não pode ser construída! • a tendência é no sentido de maior flexibilidade • TURBOPASCAL, Delphi • polimorfismos, ADTs, reflexão • exemplos tipadas não-tipadas seguras ML LISP não-seguras C Assembly
Verificação de Tipos • consiste na detecção de erros de tipos • a verificação de tipos pode ser: • Estática, durante a compilação de programas, através da análise do código fonte • Dinâmica, durante a execução do programa int x; any y; int f (int p) { … }; { • f(3); • f(x); • f(y); } • os erros devem ser detectados tão cedo quanto possível, porque: • em tempo de execução exigem informação sobre tipos disponível • a verificação de tipos atrasa a execução • o programa é dificilmente validado já que podem sempre ocorrer erros • os programadores devem dispôr de meios que lhes permitam especificar o comportamento dos programas quando um erro é detectado durante a execução • por exemplo com excepções estática dinâmica
Inferência de Tipos • as linguagens podem ter tipos explícitos na sintaxe • como em PASCAL ou Java • ou implícitos • como em ML ou Haskell • neste caso o sistema de tipos atribui tipos aos fragmentos do programa • a inferência de tipos é uma extensão natural da verificação de tipos • se o programador não fornece os tipos, o compilador deve extraí-los da análise do programa • exemplo em ML: fun append(nil, l) = l | append(hd:: tl, l) = hd:: append(tl, l) • o compilador de ML devolve o tipo da expressão val append = fn: ('a list * 'a list) -> 'a list • e em fun suc(x) = x + 1 • a inferência de tipos está ligada ao polimorfismo, como veremos mais tarde
Equivalência de Tipos • um algoritmo decide quando são equivalentes, em termos de tipos, duas expressões escritas independentemente • A e B são equivalentes? type A = record( x, y; real); type B = record( x, y; real); • equivalência estrutural • todos os tipos base são equivalentes • tipos construídos são equivalentes se resultam da aplicação do mesmo construtor a tipos equivalentes • e.g. SML, … • A e B são equivalentes! • equivalência por nomes • duas expressões são equivalentes se resultam da mesma avaliação de uma expressão de tipos • e.g. PASCAL, ADA, … • A e B não são equivalentes!
Formalizar um Sistema de Tipos • é necessário formalizar toda a linguagem em questão • a sintaxe • dos termos (comportamento algorítmico) • dos tipos (conhecimento estático) • o alcance (scope) dos identificadores • associa ocorrências de variáveis com as localizações onde foram ligados (binding) • estático, quando a ligação entre identificador e localização pode ser determinada por análise léxica do programa (alcance léxico) • dinâmico • um fragmento de programa pode conter variáveislivres • as regras de tipos • tem-tipo M : A • subtipo-de M <: A • equivalência de tipos A = B • contextos estáticos de tipos M: A • qual a semântica da relação tem-valor entre termos e uma colecção de resultados • os tipos do resultado e dos termos devem ser os mesmos
Teoria de Tipos • é usada para estudar problemas tais como: • se a verificação de tipos é decidível • se a verificação pode ser feita durante a compilação • senão, quais são os erros que podem aparecer em tempo de execução • se podem ser gerados verificadores de tipos a partir de uma especificação do sistema de tipos • na construção de um sistema de tipos há um compromisso entre • poder expressivo • segurança • o sistema de tipos deve ser • restritivo por forma a assegurar programas confiáveis • flexível por forma a permitir que fragmentos do programa possam ser usados noutros contextos semelhantes • sob o ponto de vista sintáctico, a teoria de tipos pode ser vista como sendo um conjunto de regras que, a partir de afirmações verdadeiras sobre tipos, permite deduzir outras afirmações verdadeiras
Regras de Tipos • asserções • proposições enunciadas como verdadeiras • as variáveis livres de estão declaradas no contexto estático de tipos • contextos são listas ordenadas de variáveis (distintas) e seus tipos , X1:A1, x2:A2, x3:A3, …, xn:An dom() = x1, x2, …, xn • julgamentos de tipos • por exemplo: M:A (“M tem o tipo A em “) true: Bool (“true tem tipo Bool “) , x: Nat x+1: Nat (“se x for do tipo Nat então x+1 é do tipo Nat “) • regras de tipos • do tipo: dado um conjunto um conjunto de premissas pode deduzir-se uma conclusão a: A (a): B • “Se é conhecido que é uma função de em e que a é do tipo A então pode deduzir-se que (a) toma valores em ”
Abstracções Proporcionadas pelas LPs • traduzem em termos abstractos os mecanismos físicos • processador, memória, … • variáveis • funções • nem todas as LP possuem funções, BASIC • com ou sem efeitos secundários (side-effects), C/Haskell • a semântica de passagem de parâmetros pode ser por valor ou por referência, SML/C++ • podem ter verdadeira estrutura em blocos ou não, Algol/C • controlo • if-then-else • for-do • repeat-until • do-while • excepções • podem servir, por exemplo, para tratar erros • no exemplo apresentado, usando ADA, quando y=0, a excepção pre-definida DATA_ERROR é devolvida e o tratamento da excepção (exception handler) especifica o comportamento do programa • o que aconteceria num programa em C? caso geral caso particular function divide (x, y: float) return float is begin return x / y; exception when DATA_ERROR => if y = 0 then return 1; else return sign(x) * MAXINT; endif end
Poder Expressivo de um Sistema de Tipos • conjunto de tipos básicos • integer, boolean, float, string • tipos enumerados, cadeias de bits, imagens • conjunto de construtores de tipos • registo ou tuplo (produto cartesiano etiquetado) • variante (soma disjunta etiquetada) • registo com variantes • colecções • array • indexado, verificação de limites • lista • car, cdr • conjunto • mas em PASCAL é bastante restritivo • sequência • Galileo, O2 • função • apontador • ADT • polimorfismo record nome: string, idade: int end; union animal: DescAnimal, vegetal: DescVegeta, mineral: DescMineral end; record nome: string, idade: int, case sexo Sexo of Mulher: olhos: DescCor end end;
Tipos de Dados Abstractos • permitem um estilo de programação que leva a software de qualidade • exemplo: • problemapilha-de-palavrasoperações criar pilha nova adicionar palavra à pilha remover a última palavra da pilha ver se a pilha está vaziarestrições só pode retirar-se uma palavra da stack se esta não estiver vazia • o programador de C • tem de conhecer os detalhes de implementação • pode aceder a informação interna e aplicar operações ilegais • o programador de ADA • usando packages pode conseguir ADTs • o compilador verifica se a pilha é usada apenas conforme especificado e não permite acesso aos elementos internos
Pilha-de-palavras em C • /* especificação */ • typedefchar[256] word; • typedefstruct stack { • int size; • word * elements; } * stack; • stack stack_create(); • void stack_insert(stack, word); • void stack_drop(stack); • char stack_empty(stack); • /* implementação */ • stack stack_create() { • stack st = malloc(sizeof(struct stack)); • st->size = 0; • st->elements = (word *) malloc(1024 * sizeof(word)); • return st; • } • void stack_insert(stack st, word w) { • strcopy(st->elements[++st->size], w); • } • void stack_drop(stack st) { • --st->size; • } • char stack_empty(stack st) { • return (st->size == 0); • } /* uso */ char w1[] = "hello"; char w2[] = "world"; stack s; s = stack_create(); stack_insert(s, w1); stack_insert(s, w2); stack_drop(s); if (stack_empty(s)) { /* do st */ }
Pilha-de-palavras em ADA • /* especificação */ • package STACKS is • type stack is private; • type word is private; • function create() return stack; • function insert (s: stack, w: word) • return stack; • function drop (s: stack) return stack; • function empty (s: stack) return boolean; • private • type word isstring; • type stack is • record • size: integer; • data: array(1...1024) of word; • end record • end • /* implementação */ • package body STACKS is • function create () return stack is • begin • s: stack; • s.size:= 0; • return s; • end; function insert (s: stack, w: word) return stack is begin s.size:= s.size +1; s.data(s.size):= w; return s; end; function drop (s: stack) return stack is begin s.size:= s.size -1; return s; end; function empty (s: stack) return boolean is begin return (s.size = 0); end; end STACKS; /* uso */ uses STACKS s: stack:= create(); s:= insert(s, "hello"); s:= insert(s, "world"); s:= drop(s); s:= drop(s); s.size;= 0; // type error!
Vantagens de Programar com ADTs • é uma técnica de desenvolvimento que leva a software de maior qualidade • agrupa na mesma unidade os dados de uma aplicação e as operações que podem ser aplicadas a esses dados • separa a especificação de tipos da implementação e torna visível apenas informação pertinente • permite a existência de diversas implementações para a mesma especificação (com diferentes desempenhos)
Polimorfismo • linguagens polimórficas • um valor, em particular uma função, pode pertencer simultaneamente a vários tipos • linguagens monomórficas • valores têm apenas um tipo que pode ser determinado quando o programa é compilado • polimorfismo introduz maior flexibilidade (e.g. a aplicação de uma função a valores de tipos diferentes) mantendo os programas seguros • como vimos • sistemas de tipos são conjuntos de restrições impostos sobre uma linguagem não tipada que limitam o número de programas correctos que podem ser escritos • na ausência de tipos não há restrições, mas os programas podem falhar • variedades de polimorfismo • ad-hoc (código diferente executado para cada tipo) • overloading • o mesmo nome é usado para funções diferentes (e.g. 3+4 e 3.0+4.0) • coercion • um argumento é convertido para o tipo esperado pela função (e.g. 3+4.0) • universal (o mesmo código é executado para cada tipo) • paramétrico • funções aplicadas a uma categoria de tipos com a mesma estrutura (e.g. lenght l) • de inclusão • funções aplicadas a tipos ligados por relações de ordem (e.g. pessoa.idade e estudante.idade)
Funções Paramétricas • ML • fun append (nil, l) = l • | append (hd:: tl, l) = hd:: append(tl, l) • é polimórfica e o seu tipo (inferido como vimos) é: • val append = fn : ('a list * 'a list) -> 'a list • (aplicada a duas listas com elementos de qualquer tipo 'a produz uma lista com elementos desse mesmo tipo) • Napier88 • let id = proc[t](x: t -> t); x • é polimórfica com tipo • proc[t](t -> t) • antes de ser usada, a função é instanciada duas vezes • com um parâmetro de tipo e com um valor desse tipo • let three = id[int](3) • também se podem conseguir versões monomórficas instanciando com um parâmetro de tipo • let idInt = id[int] • se tipos fossem considerados valores da linguagem (como em Quest) esta separação não seria necessária • A:: K A tem kind K (kinds classificam tipos e operadores de tipos) • a: A a tem tipo A (tipos classificam valores)
Tipos Paramétricos • quando definições de tipo têm estrutura semelhante, podem ser expressas num tipo paramétrico • type Pair_of_integers = int x int • type Pair_of_reals = real x real • type Pair[t] = t x t • type Pair_of_integers = pairs[int] • type Pair_of_reals = pairs[real] • um tipo paramétrico não é um tipo, é uma operação sobre tipos! • Pair_of_integers não cria um novo tipo, apenas associa um nome a uma expressão de tipos • exemplos: • type A[t] = proc(t -> t) • type B = proc[t](t -> t) • operação que associa qualquer tipo t com o tipo de funções de t em t • tipo das funções que transformam um valor do tipo t noutro valor do mesmo tipo
Subtipagem (sub-typing) • se existir uma relação de ordem entre tipos (A <: B) esta pode ser usada para: • conversão automática de tipos pelo compilador • resolver sobrecarga (overloading) de operadores • formalizar o conceito de herança • esta relação de ordem pode ser • implícita, quando é inferida usando as regras de tipos • explícita, quando é declarada na altura em que os tipos são definidos • uma combinação dos dois casos anteriores; por exemplo, apenas nos ADTs (representando entidades) a relação de ordem é explícita, para todos os outros tipos é implícita • implicitamente • type Car = [name: string, speed: int, fuel: string] • type Vehicle = [name: string, speed: int] • explicitamente • type Vehicle = [name: string, speed: int] • type Car subtype Vehicle = [name: string, speed: int, fuel: string]
Subtipagem • subtipagem em escalares (range) • n..m <: p..q sse p<=n e q>=m • subtipagem em funções • s -> t <: s' -> t' sse s' <: s e t <: t' • é a regra contravariante: domínio maior e contradomínio menor • onde uma função de um dado tipo pode ser usada, também uma função de um seu subtipo pode ser usada • subtipagem em tuplos • [a1:t1,… ,an:tn,… ,am:tm] <: [a1:u1,… ,an:un] sse • ti <: ui para i [1,n] • aparece nas linguagens Orientadas aos Ojectos
Regras de Subtipagem • top t <: any reflexiva t <: t • transitiva s <: t t <: u s <: u • funcional s' <: s t <: t' s t <: s' t' • tuplos s1 <: t1 … sn <: tn [a1:s1,…,an:sn,…,am: sm] <: [a1:t1,…,an:tn] • um valor de subtipo pode ser usado onde um valor do tipo é esperado e:t t <: u e:u
Polimorfismo de Inclusão • subtipagem é uma forma de polimorfismo • uma função que pode ser aplicada a valores de um tipo, também pode ser aplicada a valores de todos os seus subtipos • exemplo: • value g fun(x: [age: int]) x.age • tem tipo • [age: int] -> int • e pode ser aplicada a • [age:31] • ou a • [name: Jean, age: 34] • polimorfismo de inclusão pode ser combinado com paramétrico • value h = all[a <: [age: int]] fun(x: a) x.age:= 29, x • não é possível aplicar h a todos os a; admite apenas os subtipos de um dado tipo
Reflexão • “um sistema computacional é dito reflexivo se incorpora em si próprio dados representando aspectos de si próprio” • reflexão é o processo de raciocinar acerca de si próprio ou actuar em si mesmo e mudar de comportamento no curso de uma avaliação • pode ser obtida • mudando a forma como os programas são avaliados no sistema • mudando as estruturas próprias do programa • em reflexão comportamental um programa pode alterar o seu próprio significado, através: • de manipulação do seu avaliador (e.g. interpretador) • do envio de mensagens a um meta-objecto que especifica aspectos do seu comportamento (e.g. como o objecto herda da superclasse) • em reflexão linguística programas podem alterar-se directamente (e.g. gerando novas estruturas de dados ou código para ser executado) • em tempo de compilação (TRPL) • em tempo de execução (PS-algol, Napier88)
Reflexão Linguística Segura em Tempo de Execução • permite a existência de programas construídos, compilados e integrados na computação corrente • !* ... • writeString("Escreva uma expressão com i") • let theProgram = "proc(i: int -> int); " ++ readString() • let theResult = compile(theProgram) • project theResult as R onto • proc(int -> int) : newProc:= R() • string : writeString("Erros : " ++ R) • default : {} !* nunca acontece • writeString("Expressão com 10 = " ++ iformat( newProc(10) ) • !* • neste exemplo (usando a sintaxe Napier88) reflexão é conseguida através do uso de procedimento compile, de verificação de tipos dinâmica e de ligação dinâmica do resultado do programa no programa em execução
Polimorfismos e Reflexão • tanto polimorfismos como programas reflexivos • permitem abstrair detalhes • promover reutilização • polimorfismo pode ser usado quando • uma computação não depende dos tipos dos operandos permitindo que estes sejam abstraídos (paramétrico) • uma computação depende apenas parcialmente nos tipos (inclusão) • usando reflexão linguística, segura (type-safe) podem ser escritos programas • que dependem arbitrariamente nos tipos de dados que manipulam • reflexão permite escrever programas que operam em valores de tipos ainda não conhecidos na altura em que são feitos • exemplo do browser
Conclusão • sistemas de tipos • servem para estruturar os valores manipulados pelas linguagens de programação • servem os papéis: • de modelação: estruturar os dados de uma aplicação • de protecção: proteger contra usos ilícitos • as linguagens de programação têm evoluído no sentido de • tipagem forte • predominantemente estática • mas com sistemas de tipos mais flexíveis • tipos de dados abstractos (ADT) • polimorfismo paramétrico • subtipagem • bulk data types • variantes • tipos dinâmicos (any) • first-class procedures • reflexão • logo estão mais adaptadas à modelização!
Conclusão (cont) • modelos semânticos de dados • servem para descrever os aspectos estruturais da aplicação • mas têm limitações a nível • do comportamento das entidades • da implementação • dos aspectos temporais ou dinâmicos (fica-se normalmente por proposições sobre a dinâmica) • note-se que os modelos orientados aos objectos proporcionam implementação e modelização do comportamento (OMT, UML) • linguagens de programação de bases de dados (LPBD) têm por objectivo unificar a estrutura dos dados e as funções que o sistema deve implementar • LPBDs são linguagens completamente gerais, baseadas num sistema de tipos permitindo programas que podem ser validados, se possível estaticamente; como são usadas para aplicações orientadas aos dados, devem permitir a modelização de dados complexos
Como Combinar Abstrações dos Modelos Semânticos com Abstrações dos Sistemas de Tipos? • os tipos de dados abstractos dos modelos semânticos definem a estrutura • nas linguagens de programação a estrutura e as operações são definidas • os ADTs podem ser usados em conjunto com os outros valores da linguagem • o interesse especial é o que se pode fazer com as instâncias do tipo (o comportamento!) • por exemplo, a STACK em ADA • package STACKS is • type stack is private; • type word is private; • function create() return stack; • function insert (s: stack, w: word) • return stack; • function drop (s: stack) return stack; • function empty (s: stack) return boolean; • private • type word isstring; • type stack is • record • size: integer; • data: array(1...1024) of word; • end record • end • apenas existe a preocupação de dizer como o que se pode fazer com a stack e não o que é a stack • as linguagens orientadas aos objectos fornecem mecanismos para a definição de ADTs • na fronteira entre os tipos abstractos dos modelos semânticos • e os ATDs das linguagens de programação
Classe Point em Eiffel • mais geral que no exemplo apresentado em ADA • deve ser possível definir a estrutura e o comportamento num ADT • preservando as propriedades de abstracção • por exemplo, em Eiffel: • class Point export • x, y, translate, scale • feature • x, y: real • scale (f: real) is • do • x:= x * f; • y:= y * f; • end • translate (a, b: real) is • do • x:= x + a; • y:= y + b; • end • end Point • esta classe define ponto como tendo certas propriedades: • x, y atributos como nos modelos semânticos • scale, translate operações
Herança • conceito muito sobrecarregado • linguagem • subtipagem • tipos paramétricos • módulos • classificações • modelação • especificação incremental Empregado is-a Pessoa • polimorfismo paramétrico Set[Pessoa] is-a Set[t] • implementação Dictionary[t] is-a Set[t] • modularidade • classes com papel de módulos (Eiffel) • especialização e generalização Red-cars class ( Car ) = Cars / colour = red Human-being class = Men Union Women
Classes e Relações • classe é um conceito de extensão • agrupa várias entidades com propriedades semelhantes • a existência de uma entidade está ligada à pertença a uma classe e as classes organizam-se em hierarquias • conjuntos não são suficientes para representar classes • relação representa ligações não direccionais entre entidades • registos e atributos das linguagens de programação representam ligações direccionais entre entidades (pessoa -> idade) • relações podem ter chaves • e métodos de acesso específicos • nos esquemas relacionais temos • relações para representar classes de entidades • relações para representar ligações (não direccionais) entre entidades pertencendo a classes • classes e relações são mecanismos independentes e uma LPBD deve ter ambos!
Tipos Abstractos e Independência Lógica • a parte de interface de ADTs pode ter várias representações • exemplo • com edifícios com a entrada dependente do monumento e noutros determinada pela C.M. • type Cidade is abstract nome: string entradas: floatendtype Monumento is abstract name: string cidade: Cidade entrada: floatendlet CriarMonumento= fun(n: string, c: Cidade, e: float) Monumento( nome= n, cidade= t, entrada= e)let CriarMonumentoCamarario = fun(n: string, c: Cidade) Monumento( nome= n, cidade= t, derived entrada= t.entradas) • preservando uma interface simples para a manipulação de dados, podem ser representadas situações complexas com ADTs e o conceito de dados derivados • é um passo no sentido da independência lógica!
modulo 2 vista 1 Módulos e Esquemas de BDs • um módulo é um espaço para nomes • module Pessoalexport Pessoa, Empregadotype Pessoa …type Empregado ……endmodule Propriedadesexport Cidade, Monumento, …type Cidade …type Monumento … …endmodule Aplicação import Pessoal, Propriedade export Consultar, Criar, Modificar …end • o esquema das BDs representa a totalidade da informação • vistas são usadas para derivar representações secundárias • com módulos a definição é descentralizada • menor complexidade na definição do esquema, melhor controlo de evolução, definição de vistas resume-se à definição de módulos • deve ser procurada uma síntese entre as técnicas de modelação de BDs e de Engenharia de Software! vista 1 vista 2 esquema modulo 1 modulo 3 vista 2
Conclusão • uma LPBD deve beneficiar dos avanços • nos modelos de dados e • nas linguagens de programação • o centro da integração de conceitos dos dois domínios reside nos tipos de dados abstractos • mais á frente veremos que os ADTs das linguagens orientadas aos objectos são ainda mais convenientes! • subtipagem é importante pois permite uma definição incremental dos tipos de uma aplicação • o mecanismo de excepções pode ser usado nas LPBDs para tratar da violação de restrições de integridade; estas restrições devem ser especificadas globalmente e de forma declarativa • o modelo de transacções numa LPBD tem de ser bastante mais sofisticado do que nos sistemas relacionais já que os processamentos são mais complexos • “nested transactions”, por exemplo
Dos Conceitos para os Sistemas ERDBMS Exodus, Genesis,Starbus, Sabrina,Postgres Modelo Relacional ADT Lógica modelos Ada, Clu datalog NF2 Lógica + NF2 modelos NF2 OOPL + identidade LDL, Col, Nail Smalltalk, C++ Modelos OODB outras linguagens Semântico Gemstone, Iris,Orion, O2 IFO, Daplex, FQL PPL PS-algol,Napier88, Pascal-R
Linguagens de Programação de BDs extensões ao modelo relacional Pascal-R integrar características SGBD numa LP Adaplex LPBD PS-algol persistência Napier88 orientação aos objectos
Extensões ao Modelo Relacional 1) modelos com valores estruturados • modelos NF2 (non-first normal form) 2) modelos dedutivos e programação em lógica • datalog, LDL 3) modelos de objectos com identidade • O2 4) sistemas extensíveis • Exodus, Starbust, Genesis, Postgres
Modelos com Valores Estruturados • no modelo relacional temos: • conjuntos • tuplos (que não são cidadãos de primeira) • atributos atómicos • generalizando os domínios possíveis para os atributos para valores complexos não 1NF • tuplos (relações hierárquicas) • se v1, v2, …, vn são valores e a1, a2, …, an são atributos então [v1:a1, …, vn:an] é um tuplo • conjuntos (relações encaixadas) • se v1, v2, …, vn são valores distintos então {v1, …, vn} é um conjunto • por exemplo: • { [nome: "Torre dos Clérigos", endereco: [cidade: "Porto", rua: "Carmelitas"], fechado_em: {"Natal", "Páscoa", "10 Junho"}, entrada: 350.0 ] [nome: "Museu Soares dos Reis", endereco: [cidade: "Porto", rua: "D. Manuel II"], fechado_em: {"Natal", "Páscoa", "10 Junho"}, entrada: 650.0 ] [nome: "Estádio das Antas", endereco: [cidade: "Porto", rua: "Fernão de Magalhães"], fechado_em: {"Natal", "Páscoa"}, entrada: 1500.0 ]}
Modelos Dedutivos e Programação em Lógica • Prolog: • factos + regras • podem ser inferidos outros factos usando regras e factos • Bases de dados dedutivas resultam da aplicação desta mesma visão • duas aproximações • factos são gerados sempre que é adicionado um novo facto ou regra • factos são gerados apenas como resposta a interrogações • os predicados Prolog podem ser vistos com um conjunto de tuplos (relações) • mas nas bases de dados • o desempenho é crucial • existem linguagens que trabalham ao nível do tuplo (em Prolog só um tuplo de cada vez) • as quantidades de dados são muito grandes • a aproximação lógica tem como vantagens • apresentar um formalismo uniforme e de nível superior para definir dados, vistas e restrições de integridade • permitir a existência de linguagens baseadas em regras de dedução • não haver distinção entre processamento de dados gerais e dados da base de dados (ver desadaptação de impedâncias) • exemplos: • Datalog, cláusulas de Horn sem funções • LDL, extensão ao Datalog com conjuntos e operações em conjuntos, e funções pré-definidas
Modelos de Objectos com Identidade • nestes modelos a identidade aparece de forma explícita • é um nome dado a cada objecto da base de dados • no modelo relacional 2 tuplos são considerados iguais se contiverem os mesmos valores • a identidade permite a partilha de dados • por exemplo: • clerigos= [nome: "Torre dos Clérigos", endereco: [cidade: porto, rua: "Carmelitas"], fechado_em: {"Natal", "Páscoa", "10 Junho"}, entrada: 350.0]pilar= [nome: "Mosteiro da Serra do Pilar", endereco: [cidade: gaia, rua: "Av. República"], fechado_em: {"Natal", "Páscoa", "10 Junho"}, entrada: 350.0]museu= [nome: "Museu Soares dos Reis", endereco: [cidade: porto, rua: "D. Manuel II"], fechado_em: {"Natal", "Páscoa", "10 Junho"}, entrada: 650.0]porto= [nome: "Porto", população= 800000, estacoes= {"Campanhã", "S. Bento", "Trindade"} ] • gaia= [nome: "Vila Nova de Gaia", população= 350000, estacoes= {"Devesas", "Gaia"} ]