Bases de dados OO Sumário Conceitos gerais Exemplo do ObjectStore) Arquitectura Criação de objectos Gestão da concorrência Colecções Perguntas Índices Associações BDOO - 0 Perguntas acesso navegacional versus acesso associativo (por chave, etc.) optimizador de perguntas minimiza o número de objectos examinados para obter uma colecção dos elementos que satisfazem uma dada condição os_Collection<E> &query( char *type_string, char *query_string, os_database *schema_database = 0, char *file_name = 0, BD da colecção ou BD do esquema da aplicação os_unsigned_int32 line = 0, ficheiro fonte e linha do erro os_boolean dups = query_dont_preserve_duplicates elimina duplicados ) const Pergunta típica: expressão-de-colecção.query( nome-do-tipo-dos-elementos, pergunta, a colecção resultante é colocada na heap: eliminar com delete() BD-esquema) BDOO - 1 Exemplo de uma pergunta os_database *people_database; os_Set<person*> *people; … os_Set<person*> &teenagers= people->query( "person*", "this->age >= 13 && this->age <= 19", people_database); os_database *people_database; os_Set<person*> *people; • tipo dos elementos • uma pergunta é uma expressão de controlo; um elemento e satisfaz o critério de selecção se a expressão de controlo avaliar para true quando e está ligado a this • qualquer expressão de tipo int serve, desde que - sem variáveis, só com membros dados - funções, só strcmp(), strcoll(), comparadores com função de ordem registada e funções que retornem um apontador ou tipo aritmético e não tenham argumentos para além de this … os_Set<person*> &teenagers= people->query( "person*", • this está implícito para os membros da classe age >= 13 && age <= 19", people_database); BDOO - 2 Outras formas de pergunta elemento isolado (optimização) E query_pick(char*, char*, os_database*) const os_database *parts_database; os_Set<part*> *parts; … part *part_number_411= parts->query_pick( query_pick <=> query + os_collection::pick() "part*", "part_number == 411", parts_database); perguntas existenciais: forma semelhante, mas devolvem um os_int32, em vez de elementos BDOO - 3 Perguntas encaixadas nas três formas de pergunta é possível introduzir subperguntas expressão-de-colecção[:expressão-int:] expressão-de-colecção dá um elemento da expressão principal e expressão-int o critério de selecção para a pergunta encaixada expressão-de-colecção[%expressão-int%] //nesta forma só dá um elemento processamento de subperguntas semelhante, excepto que a colecção resultante é convertida para inteiro; resultado vazio,dá falso, não vazio, verdade os_database *db; os_Set<part*> &a_set …; a_set->query("part*", "children[:1:]",db); • todos os componentes com filhos: - para cada elemento e em a_set tem-se que e->children[:1:] devolve e->children o qual é convertido para true se não estiver vazio e portanto e fica no resultado • a_set->query("part*", "!children[:1:]",db); os_database *db; part *a_part; a_part->(descendents()->query("part*", "children[:1:] && !children[:children:]",db); • os componentes cujos filhos são todos primitivos • componentes sem filhos BDOO - 4 Perguntas pré-analisadas partes da avaliação de uma pergunta • análise da expressão • ligação das variáveis livres e das referências de função, i.e., todos os identificadores excepto membros • interpretação efectiva da pergunta ligada se a mesma pergunta for executada várias vezes, vale a pena guardar o resultado da análise num objecto da classe os_coll_query (pode ser criado com create, create_pick, create_exists) pois a análise é uma fase pesada. const os_coll_query &age_range_query= —analisada os_coll_query::create( "person*", "age >= *(int*)min_age_ptr && age <= *(int*)max_age_ptr, db1); int teenage_min_age=13, teenage_max_age =19; os_bound_query teenage_range_query( age_range_query. —ligada (os_keyword_arg("min_age_ptr", &teenage_min_age), os_keyword_arg("max_age_ptr", &teenage_max_age) ) ); people.query(teenage_range_query); — invocação BDOO - 5 Bases de dados OO Sumário Conceitos gerais Exemplo do ObjectStore) Arquitectura Criação de objectos Gestão da concorrência Colecções Perguntas Índices Associações BDOO - 6 Índices os índices servem para optimizar certos caminhos de acesso, obtendo comportamentos melhores que linear nos casos em que é possível a_set->query_pick("part*", "part_number==411", db1); especificar que se pretende o índice no conjunto a_set e que a chave do índice é o membro part_number — usar os_collection::add_index(); • os_Set<part*> *a_set; os_index_path &key_spec = os_index_path::create("part*","part_number", db1); a_set->add_index(key_spec • para remover o índice: drop_index() • qualquer acesso por este caminho resulta mais eficiente caminhos que terminem em cadeias originam índices com a cadeia na chave os outros caminhos que terminam em apontadores são optimizados por endereço os índices têm que ser mantidos, quando há alterações de elementos que estão no respectivo caminho — atrasa as actualizações; acelera as pesquisas, pelo que só se deve usar índices quando não há muitas modificações pode-se adicionar e eliminar índices durante a vida da colecção, conforme a conveniência; o optimizador de perguntas adapta-se dinamicamente BDOO - 7 Opções nos índices para testar a existência de índices (dois índices com o mesmo caminho são o mesmo) • if(a_set->has_index(key_spec)) ... • os_collection::get_indexes() podem ser utilizados caminhos complexos • os_index_path::create("part*","(*responsible_engineers)[]->emp_id) o índice de número de componente para componente é implementado via tabelas de dispersão — fica desordenado havendo pesquisas por gama em número de componente, convém que o índice esteja ordenado — especificar a opção a_set->add_index(a_path, os_index_path::ordered) para implementar em árvores-B outras opções de criação incluem: • allow_duplicates, no_duplicates, signal_duplicates — tratamento dos repetidos • copy_key, point_to_key — tratamento da chave BDOO - 8 Manutenção dos índices alterações nos objectos obrigam a corrigir os índices manutenção pode ser automática, semimanual ou manual; para a manutenção automática (e também para usar membros função nos caminhos) é necessário adicionar no início da classe um membro especial: • membro do tipo os_backptr (basta um por classe; pode ser herdado, simples) class part{ public: … os_backptr b; int id; department *dept; … part(); ~part(); } • se membro declarado normalmente como value-type member-name é para indexar, usase a macro os_indexable_member(class-name, member-name, value-type) member-name • tem que se instanciar os corpos das respectivas funções os_indexable_body(class-name, member-name, value-type,backptr-spec); os_index(class,backptr-member); // = backptr-spec BDOO - 9 Notas CUIDADO: nas macros não meter espaços junto aos argumentos o valor real de um membro dado indexável é um objecto contentor especial, que encapsula o valor aparente REAL APARENTE contentor int a_part->id.setvalue(411) a_part->id = 411 f(a_part->id.getvalue()) f(a_part->id) conclusão: a manutenção dos índices fica praticamente automática; só nos locais onde se perde a informação de tipo (printf) é necessário forçar o cast printf("The idis %d \n", (int)(a_part->id)); a manutenção dos índices nas inserções e remoções de colecções é automática a manutenção manual está a cargo de funções como make_link() e break_link() BDOO - 10 Bases de dados OO Sumário Conceitos gerais Exemplo do ObjectStore) Arquitectura Criação de objectos Gestão da concorrência Colecções Perguntas Índices Associações BDOO - 11 Integridade A manutenção da integridade dos dados é um dos serviços mais valiosos de um SGBD Exemplo estruturas de dados com nós Lista duplamente ligada Árvore Grafo • como representar em termos de classes? • os três exemplos podem ser vistos como casos particulares da representação de uma relação binária entre nós BDOO - 12 Membros inversos representação da relação binária através da inclusão de um membro em cada uma das classes envolvidas na associação • o problema é manter a consistência, pois a informação dos dois lados não é independente: os dois membros representam a relação e a sua inversa • ObjectStore garante a manutenção automática do sincronismo entre membros declarados como inversos • o código que usa membros inversos está escrito como se eles fossem normais a manutenção dos inversos é feita através de uma classe embebida que encapsula os apontadores, de forma a interceptar as respectivas alterações e manter a integridade referencial • é necessário incluir os ficheiros ostore.hh, coll.hh, relat.hh • existem três interfaces para a classe associação(ex: componentes e peças) - other = some->container; // membro de dados simples - other = some->container.getvalue(); // associação - other = some->get_container(); // funcional - some->container = other; // membro de dados simples - some->container.setvalue(other); // associação - some->set_container(other); // funcional BDOO - 13 Definição das associações definem-se as associações e usam-se macros para os respectivos corpos • definições - os_relationship_1_1 um-para-um - os_relationship_1_m um-para-muitos - os_relationship_m_1 muitos-para-um - os_relationship_m_m muitos-para-muitos • macros para os corpos respectivos - os_rel_1_1_body um-para-um - os_rel_1_m_body um-para-muitos - os_rel_m_1_body muitos-para-um - os_rel_m_m_body muitos-para-muitos • argumentos: classe do membro, membro, classe do membro inverso, membro inverso, tipo do membro (as macros dos corpos não têm este argumento) os_relationship_1_m(person, employer, company, employees, company*) employer as alterações num membro nem sempre provocam alterações no inverso: só nestes casos é obrigatório: - associação um-um - associação um-muitos, colecção não aceita duplicados - associação muitos-muitos, ambas as colecções permitem (proibem) duplicados BDOO - 14 Associações um-um Lista duplamente ligada: cada nó tem um seguinte e um anterior, declarados com inversos #include <ostore/relat.hh> class node { public: os_relationship_1_1(node,next,node,previous,node*) next; os_relationship_1_1(node,previous,node, next,node*) previous; node(){}; }; os_rel_1_1_body(node,next,node,previous); os_rel_1_1_body(node, previous,node, next); main(){ objectstore::initialize(); os_collection::initialize(); node* n1 = new node(); node* n2 = new node(); n1->next = n2; //actualiza auto. n2->previous printf("n1 (%x) --> (%x)\n",n1,n1.next.get_value(); printf("n2 (%x) --> (%x)\n",n2,n2.previous.get_value(); BDOO - 15 Comentários responsabilidade: sobrecarga do operador =() e dos operadores de coerção n1->next = n2->next; é interpretado como n1->next.operator=(n2->next.operator node*() ); printf precisa de coerção, porque não tem informação prototípica nos argumentos printf("The value is %x\n, (node*)n1->next) BDOO - 16 Associações muitos-um Árvore: cada nó tem um só pai (excepto a raiz) e zero ou mais filhos #include <ostore/relat.hh> class node { public: os_relationship_1_m(node,parent,node,children,node*) parent; os_relationship_m_1(node,children,node, parent,os_collection) children; node(){}; }; os_rel_1_m_body( node,parent,node,children ); os_rel_m_1_body( node,children,node, parent ); main(){ objectstore::initialize(); os_collection::initialize(); node* n1 = new node(); node* n2 = new node(); n1->children.insert( n2); //actualiza auto. n2->parent // daria o mesmo ter escrito n2->parent=n1 BDOO - 17