Buscar

La cara oculta de C Builder

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 797 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 797 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 797 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

kuera
La cara oculta de
C++ Builder
kuera
Un gato camina sobre el borde del tejado;
Tras él, el Sol se pone.
Gira su cara hacia mí, y creo que me sonríe.
Luego, de un salto, pasa sobre la línea del horizonte.
Dedicado a Vivian, dondequiera que esté.
Ian \
INDICEINDICE
PRÓLOGO DEL AUTOR 17
CONTENIDO DEL LIBRO 17
AGRADECIMIENTOS 19
EL LENGUAJE SQL 21
1. SISTEMAS DE BASES DE DATOS 23
ACERCA DEL ACCESO TRANSPARENTE A BASES DE DATOS 23
BASES DE DATOS RELACIONALES 24
INFORMACIÓN SEMÁNTICA = RESTRICCIONES 26
RESTRICCIONES DE UNICIDAD Y CLAVES PRIMARIAS 27
INTEGRIDAD REFERENCIAL 28
¿QUÉ TIENE DE MALO EL MODELO RELACIONAL? 29
BASES DE DATOS LOCALES Y SERVIDORES SQL 31
CARACTERÍSTICAS GENERALES DE LOS SISTEMAS SQL 33
EL FORMATO PARADOX 34
EL FORMATO DBF7 37
CRITERIOS PARA EVALUAR UN SERVIDOR SQL 39
INTERBASE 41
MICROSOFT SQL SERVER 43
ORACLE 45
OTROS SISTEMAS DE USO FRECUENTE 46
2. BREVE INTRODUCCIÓN A SQL 49
LA ESTRUCTURA DE SQL 49
PARA SEGUIR LOS EJEMPLOS DE ESTE LIBRO… 50
LA CREACIÓN Y CONEXIÓN A LA BASE DE DATOS 52
TIPOS DE DATOS EN SQL 53
REPRESENTACIÓN DE DATOS EN INTERBASE 54
CREACIÓN DE TABLAS 55
COLUMNAS CALCULADAS 56
VALORES POR OMISIÓN 57
RESTRICCIONES DE INTEGRIDAD 57
CLAVES PRIMARIAS Y ALTERNATIVAS 58
INTEGRIDAD REFERENCIAL 60
ACCIONES REFERENCIALES 61
NOMBRES PARA LAS RESTRICCIONES 62
4 La Cara Oculta de C++ Builder
DEFINICIÓN Y USO DE DOMINIOS 63
CREACIÓN DE ÍNDICES 64
MODIFICACIÓN DE TABLAS E ÍNDICES 65
CREACIÓN DE VISTAS 66
CREACIÓN DE USUARIOS 66
ASIGNACIÓN DE PRIVILEGIOS 68
ROLES 69
UN EJEMPLO COMPLETO DE SCRIPT SQL 70
3. CONSULTAS Y MODIFICACIONES 73
LA INSTRUCCIÓN SELECT: EL LENGUAJE DE CONSULTAS 73
LA CONDICIÓN DE SELECCIÓN 75
OPERADORES DE CADENAS 75
YO SÓLO QUIERO LOS DIEZ PRIMEROS... 76
EL VALOR NULO: ENFRENTÁNDONOS A LO DESCONOCIDO 77
ELIMINACIÓN DE DUPLICADOS 78
PRODUCTOS CARTESIANOS Y ENCUENTROS 79
ORDENANDO LOS RESULTADOS 81
EL USO DE GRUPOS 82
FUNCIONES DE CONJUNTOS 83
LA CLÁUSULA HAVING 84
EL USO DE SINÓNIMOS PARA TABLAS 85
SUBCONSULTAS: SELECCIÓN ÚNICA 86
SUBCONSULTAS: LOS OPERADORES IN Y EXISTS 87
SUBCONSULTAS CORRELACIONADAS 88
EQUIVALENCIAS DE SUBCONSULTAS 89
ENCUENTROS EXTERNOS 91
LA CURIOSA SINTAXIS DEL ENCUENTRO INTERNO 93
LAS INSTRUCCIONES DE ACTUALIZACIÓN 94
LA SEMÁNTICA DE LA INSTRUCCIÓN UPDATE 95
VISTAS 96
4. PROCEDIMIENTOS ALMACENADOS Y TRIGGERS 99
¿PARA QUÉ USAR PROCEDIMIENTOS ALMACENADOS? 99
CÓMO SE UTILIZA UN PROCEDIMIENTO ALMACENADO 101
EL CARÁCTER DE TERMINACIÓN 102
PROCEDIMIENTOS ALMACENADOS EN INTERBASE 103
PROCEDIMIENTOS QUE DEVUELVEN UN CONJUNTO DE DATOS 106
RECORRIENDO UN CONJUNTO DE DATOS 108
TRIGGERS, O DISPARADORES 109
LAS VARIABLES NEW Y OLD 111
MÁS EJEMPLOS DE TRIGGERS 111
GENERADORES 113
Indice 5
SIMULANDO LA INTEGRIDAD REFERENCIAL 116
EXCEPCIONES 117
ALERTADORES DE EVENTOS 119
FUNCIONES DE USUARIO EN INTERBASE 121
5. TRANSACCIONES 125
¿POR QUÉ NECESITAMOS TRANSACCIONES? 125
EL ÁCIDO SABOR DE LAS TRANSACCIONES 127
TRANSACCIONES SQL Y EN BASES DE DATOS LOCALES 128
TRANSACCIONES IMPLÍCITAS Y EXPLÍCITAS 128
NIVELES DE AISLAMIENTO DE TRANSACCIONES 131
REGISTROS DE TRANSACCIONES Y BLOQUEOS 133
LECTURAS REPETIBLES MEDIANTE BLOQUEOS 136
VARIACIONES SOBRE EL TEMA DE BLOQUEOS 138
EL JARDÍN DE LOS SENDEROS QUE SE BIFURCAN 139
¿BLOQUEOS O VERSIONES? 141
NIVELES DE AISLAMIENTO Y TRANSACCIONES IMPLÍCITAS 143
6. MICROSOFT SQL SERVER 145
HERRAMIENTAS DE DESARROLLO EN EL CLIENTE 145
CREACIÓN DE BASES DE DATOS CON MS SQL SERVER 146
BASES DE DATOS EN LA VERSIÓN 7 148
TIPOS DE DATOS PREDEFINIDOS 149
TIPOS DE DATOS DEFINIDOS POR EL PROGRAMADOR 150
CREACIÓN DE TABLAS Y ATRIBUTOS DE COLUMNAS 151
INTEGRIDAD REFERENCIAL 152
INDICES 153
SEGURIDAD EN MS SQL SERVER 153
PROCEDIMIENTOS ALMACENADOS 154
CURSORES 155
TRIGGERS EN TRANSACT-SQL 157
INTEGRIDAD REFERENCIAL MEDIANTE TRIGGERS 159
TRIGGERS ANIDADOS Y TRIGGERS RECURSIVOS 161
7. ORACLE 163
SOBREVIVIENDO A SQL*PLUS 163
INSTANCIAS, BASES DE DATOS, USUARIOS 165
TIPOS DE DATOS 166
CREACIÓN DE TABLAS 167
INDICES EN ORACLE 168
ORGANIZACIÓN FÍSICA DE LAS TABLAS 169
PROCEDIMIENTOS ALMACENADOS EN PL/SQL 171
CONSULTAS RECURSIVAS 172
6 La Cara Oculta de C++ Builder
PLANES DE OPTIMIZACIÓN EN ORACLE 173
CURSORES 174
TRIGGERS EN PL/SQL 176
LA INVASIÓN DE LAS TABLAS MUTANTES 177
PAQUETES 179
ACTUALIZACIÓN DE VISTAS MEDIANTE TRIGGERS 181
SECUENCIAS 182
TIPOS DE OBJETOS 184
8. DB2 UNIVERSAL DATABASE 189
ARQUITECTURA Y PLATAFORMAS 189
AISLAMIENTO DE TRANSACCIONES 190
TIPOS DE DATOS 191
CREACIÓN DE TABLAS Y RESTRICCIONES 193
INDICES 194
TRIGGERS 195
CONSULTAS RECURSIVAS 196
PROCEDIMIENTOS ALMACENADOS 198
9. EL MOTOR DE DATOS DE BORLAND 199
QUÉ ES, Y CÓMO FUNCIONA 200
CONTROLADORES LOCALES Y SQL LINKS 201
ACCESO A FUENTES DE DATOS ODBC 202
¿DÓNDE SE INSTALA EL BDE? 202
EL ADMINISTRADOR DEL MOTOR DE DATOS 204
CONFIGURACIÓN DEL REGISTRO E INFORMACIÓN DE VERSIÓN 204
EL CONCEPTO DE ALIAS 206
PARÁMETROS DEL SISTEMA 206
PARÁMETROS DE LOS CONTROLADORES PARA BD LOCALES 208
BLOQUEOS OPORTUNISTAS 210
PARÁMETROS COMUNES A LOS CONTROLADORES SQL 211
CONFIGURACIÓN DE INTERBASE 214
CONFIGURACIÓN DE MS SQL SERVER 216
CONFIGURACIÓN DE ORACLE 217
CONFIGURACIÓN DE OTROS SISTEMAS 219
CREACIÓN DE ALIAS PARA BASES DE DATOS LOCALES Y SQL 219
ALTERNATIVAS AL MOTOR DE DATOS 220
C++ BUILDER: NAVEGACIÓN Y BÚSQUEDAS 221
10. CONJUNTOS DE DATOS: TABLAS 223
LA JERARQUÍA DE LOS CONJUNTOS DE DATOS 223
Indice 7
LA ARQUITECTURA DE OBJETOS DEL MOTOR DE DATOS 225
¿TABLA O CONSULTA? 227
TABLAS (POR EL MOMENTO) 229
EXCLUSIVIDAD Y BLOQUEOS 231
CONEXIÓN CON COMPONENTES VISUALES 232
NAVEGANDO POR LAS FILAS 234
MARCAS DE POSICIÓN 235
ENCAPSULAMIENTO DE LA ITERACIÓN 236
LA RELACIÓN MASTER/DETAIL 239
NAVEGACIÓN Y RELACIONES MASTER/DETAIL 242
EL ESTADO DE UN CONJUNTO DE DATOS 247
11. ACCESO A CAMPOS 249
CREACIÓN DE COMPONENTES DE CAMPOS 249
CLASES DE CAMPOS 251
NOMBRE DEL CAMPO Y ETIQUETA DE VISUALIZACIÓN 253
ACCESO A LOS CAMPOS POR MEDIO DE LA TABLA 254
EXTRAYENDO INFORMACIÓN DE LOS CAMPOS 255
LAS MÁSCARAS DE FORMATO Y EDICIÓN 256
LOS EVENTOS DE FORMATO DE CAMPOS 258
CAMPOS CALCULADOS 259
CAMPOS DE BÚSQUEDA 261
LA CACHÉ DE BÚSQUEDA 263
EL ORDEN DE EVALUACIÓN DE LOS CAMPOS 264
EXTENSIONES PARA LOS TIPOS DE OBJETOS DE ORACLE 8 265
INFORMACIÓN SOBRE CAMPOS 268
CREACIÓN DE TABLAS 269
12. VALIDACIONES Y EL DICCIONARIO DE DATOS 273
VALIDACIÓN A NIVEL DE CAMPOS 273
PROPIEDADES DE VALIDACIÓN 274
EL DICCIONARIO DE DATOS 275
CONJUNTOS DE ATRIBUTOS 276
IMPORTANDO BASES DE DATOS 277
EVALUANDO RESTRICCIONES EN EL CLIENTE 278
13. CONTROLES DE DATOS Y FUENTES DE DATOS 281
CONTROLES DATA-AWARE 281
LOS ENLACES DE DATOS 283
CREACIÓN DE CONTROLES DE DATOS 284
LOS CUADROS DE EDICIÓN 285
EDITORES DE TEXTO 286
TEXTOS NO EDITABLES 287
8 La Cara Oculta de C++ Builder
COMBOS Y LISTAS CON CONTENIDO FIJO 287
COMBOS Y LISTAS DE BÚSQUEDA 290
ESENCIA Y APARIENCIA 292
CASILLAS DE VERIFICACIÓN Y GRUPOS DE BOTONES 292
IMÁGENES EXTRAÍDAS DE BASES DE DATOS 293
LA TÉCNICA DEL COMPONENTE DEL POBRE 293
PERMITIENDO LAS MODIFICACIONES 295
BLOB, BLOB, BLOB… 297
LA CLASE TBLOBSTREAM 298
14. REJILLAS Y BARRAS DE NAVEGACIÓN 301
EL USO Y ABUSO DE LAS REJILLAS 301
EL FUNCIONAMIENTO BÁSICO DE UNA REJILLA DE DATOS 302
OPCIONES DE REJILLAS 304
COLUMNAS A LA MEDIDA 304
GUARDAR Y RESTAURAR LOS ANCHOS DE COLUMNAS 307
LISTAS DESPLEGABLES Y BOTONES DE EDICIÓN 308
NÚMEROS VERDES Y NÚMEROS ROJOS 309
MÁS EVENTOS DE REJILLAS 312
LA BARRA DE DESPLAZAMIENTO DE LA REJILLA 313
REJILLAS DE SELECCIÓN MÚLTIPLE 313
BARRAS DE NAVEGACIÓN 314
HABÍA UNA VEZ UN USUARIO TORPE, MUY TORPE… 315
AYUDAS PARA NAVEGAR 316
EL COMPORTAMIENTO DE LA BARRA DE NAVEGACIÓN 316
REJILLAS DE CONTROLES 318
15. INDICES 321
CON QUÉ ÍNDICES PODEMOS CONTAR 321
ESPECIFICANDO EL ÍNDICE ACTIVO 323
INDICES EN DBASE 325
ESPECIFICANDO UN ORDEN EN TABLAS SQL 326
BÚSQUEDA BASADA EN ÍNDICES 327
IMPLEMENTACIÓN DE REFERENCIAS MEDIANTE FINDKEY 329
BÚSQUEDAS UTILIZANDO SETKEY 330
EXPERIMENTANDOCON SETKEY 330
¿POR QUÉ EXISTE SETKEY? 332
RANGOS: DESDE EL ALFA A LA OMEGA 333
EL EJEMPLO DE RANGOS DE CASI TODOS LOS LIBROS 335
MÁS PROBLEMAS CON LOS ÍNDICES DE DBASE 336
CÓMO CREAR UN ÍNDICE TEMPORAL 337
Indice 9
16. MÉTODOS DE BÚSQUEDA 341
FILTROS 341
ESTO NO LO DICE LA DOCUMENTACIÓN… 342
UN EJEMPLO CON FILTROS RÁPIDOS 343
EL EVENTO ONFILTERRECORD 346
LOCALIZACIÓN Y BÚSQUEDA 347
UN DIÁLOGO GENÉRICO DE LOCALIZACIÓN 350
FILTROS LATENTES 352
FILTER BY EXAMPLE 354
BÚSQUEDA EN UNA TABLA DE DETALLES 358
17. NAVEGACIÓN MEDIANTE CONSULTAS 361
EL COMPONENTE TQUERY COMO CONJUNTO DE DATOS 361
¿QUIÉN EJECUTA LAS INSTRUCCIONES? 362
CONSULTAS ACTUALIZABLES 363
SIEMPRE HACIA ADELANTE 365
CONSULTAS PARAMÉTRICAS 368
CONSULTAS DEPENDIENTES 370
LA PREPARACIÓN DE LA CONSULTA 371
VISUAL QUERY BUILDER 373
18. COMUNICACIÓN CLIENTE/SERVIDOR 377
NUESTRA ARMA LETAL: SQL MONITOR 377
APERTURA DE TABLAS Y CONSULTAS 378
LA CACHÉ DE ESQUEMAS 380
OPERACIONES DE NAVEGACIÓN SIMPLE 380
BÚSQUEDAS EXACTAS CON LOCATE 381
BÚSQUEDAS PARCIALES 382
UNA SOLUCIÓN PARA BÚSQUEDAS PARCIALES RÁPIDAS 383
BÚSQUEDAS CON FILTROS LATENTES 384
C++ BUILDER: ACTUALIZACIONES Y CONCURRENCIA 387
19. ACTUALIZACIONES 389
LOS ESTADOS DE EDICIÓN Y LOS MÉTODOS DE TRANSICIÓN 389
ASIGNACIONES A CAMPOS 390
CONFIRMANDO LAS ACTUALIZACIONES 392
DIFERENCIAS ENTRE INSERT Y APPEND 393
COMO POR AZAR… 394
MÉTODOS ABREVIADOS DE INSERCIÓN 395
EL GRAN EXPERIMENTO 396
10 La Cara Oculta de C++ Builder
EL GRAN EXPERIMENTO: TABLAS LOCALES 397
EL GRAN EXPERIMENTO: TABLAS SQL 398
PESIMISTAS Y OPTIMISTAS 399
EL MODO DE ACTUALIZACIÓN 400
LA RELECTURA DEL REGISTRO ACTUAL 402
ELIMINANDO REGISTROS 404
ACTUALIZACIÓN DIRECTA VS VARIABLES EN MEMORIA 404
AUTOMATIZANDO LA ENTRADA DE DATOS 406
ENTRADA DE DATOS CONTINUA 408
20. ACTUALIZACIONES MEDIANTE CONSULTAS 411
INSTRUCCIONES DEL DML 411
ALMACENAR EL RESULTADO DE UNA CONSULTA 412
¿EJECUTAR O ACTIVAR? 413
NUEVAMENTE COMO POR AZAR.... 416
ACTUALIZACIÓN SOBRE CURSORES DE CONSULTAS 417
UTILIZANDO PROCEDIMIENTOS ALMACENADOS 418
21. EVENTOS DE TRANSICIÓN DE ESTADOS 421
CUANDO EL ESTADO CAMBIA… 421
REGLAS DE EMPRESA: ¿EN EL SERVIDOR O EN EL CLIENTE? 422
INICIALIZACIÓN DE REGISTROS: EL EVENTO ONNEWRECORD 423
VALIDACIONES A NIVEL DE REGISTROS 424
ANTES Y DESPUÉS DE UNA MODIFICACIÓN 425
PROPAGACIÓN DE CAMBIOS EN CASCADA 427
ACTUALIZACIONES COORDINADAS MASTER/DETAIL 428
ANTES Y DESPUÉS DE LA APERTURA DE UNA TABLA 429
TIRANDO DE LA CADENA 430
LOS EVENTOS DE DETECCIÓN DE ERRORES 431
LA ESTRUCTURA DE LA EXCEPCIÓN EDBENGINEERROR 432
APLICACIONES DE LOS EVENTOS DE ERRORES 436
UNA VEZ MÁS, LA ORIENTACIÓN A OBJETOS… 438
22. BASES DE DATOS Y TRANSACCIONES 439
EL COMPONENTE TDATABASE 439
OBJETOS DE BASES DE DATOS PERSISTENTES 440
CAMBIANDO UN ALIAS DINÁMICAMENTE 441
BASES DE DATOS Y CONJUNTOS DE DATOS 443
PARÁMETROS DE CONEXIÓN 444
LA PETICIÓN DE CONTRASEÑAS 445
EL DIRECTORIO TEMPORAL DE WINDOWS 447
COMPARTIENDO LA CONEXIÓN 448
CONTROL EXPLÍCITO DE TRANSACCIONES 449
Indice 11
ENTRADA DE DATOS Y TRANSACCIONES 450
23. SESIONES 453
¿PARA QUÉ SIRVEN LAS SESIONES? 453
ESPECIFICANDO LA SESIÓN 454
CADA SESIÓN ES UN USUARIO 454
EL INICIO DE SESIÓN Y LA INICIALIZACIÓN DEL BDE 455
SESIONES E HILOS PARALELOS 457
INFORMACIÓN SOBRE ESQUEMAS 460
EL MINIEXPLORADOR DE BASES DE DATOS 461
GESTIÓN DE ALIAS A TRAVÉS DE TSESSION 463
DIRECTORIOS PRIVADOS, DE RED Y CONTRASEÑAS 464
24. ACTUALIZACIONES EN CACHÉ 467
¿CACHÉ PARA QUÉ? 467
ACTIVACIÓN DE LAS ACTUALIZACIONES EN CACHÉ 468
CONFIRMACIÓN DE LAS ACTUALIZACIONES 469
MARCHA ATRÁS 471
EL ESTADO DE ACTUALIZACIÓN 472
EL FILTRO DE TIPOS DE REGISTROS 473
UN EJEMPLO INTEGRAL 474
EL GRAN FINAL: EDICIÓN Y ENTRADA DE DATOS 476
COMBINANDO LA CACHÉ CON GRABACIONES DIRECTAS 478
PROTOTIPOS Y MÉTODOS VIRTUALES 482
CÓMO ACTUALIZAR CONSULTAS “NO” ACTUALIZABLES 483
EL EVENTO ONUPDATERECORD 486
DETECCIÓN DE ERRORES DURANTE LA GRABACIÓN 487
¿TABLAS ... O CONSULTAS EN CACHÉ? 489
PROGRAMACIÓN DISTRIBUIDA 491
25. CONJUNTOS DE DATOS CLIENTES 493
CREACIÓN DE CONJUNTOS DE DATOS 493
CÓMO EL TCLIENTDATASET OBTIENE SUS DATOS 495
NAVEGACIÓN, BÚSQUEDA Y SELECCIÓN 496
FILTROS 497
EDICIÓN DE DATOS 498
CONJUNTOS DE DATOS ANIDADOS 499
CAMPOS CALCULADOS INTERNOS 502
INDICES, GRUPOS Y VALORES AGREGADOS 503
12 La Cara Oculta de C++ Builder
26. EL MODELO DE OBJETOS COMPONENTES 507
UN MODELO BINARIO DE OBJETOS 507
¡YO QUIERO VER CÓDIGO! 508
CLASES, OBJETOS E INTERFACES 509
EL LENGUAJE DE DESCRIPCIÓN DE INTERFACES 511
IDENTIFICADORES GLOBALES ÚNICOS 513
INTERFACES 514
LA INTERFAZ IUNKNOWN 516
TIEMPO DE VIDA 517
INTROSPECCIÓN 518
CÓMO OBTENER UN OBJETO COM 520
PUNTEROS INTELIGENTES A INTERFACES 521
27. SERVIDORES COM 525
INTERCEPTANDO OPERACIONES EN DIRECTORIOS 525
DENTRO DEL PROCESO, EN LA MISMA MÁQUINA, REMOTO... 526
CARGA Y DESCARGA DE LA DLL 529
OLE Y EL REGISTRO DE WINDOWS 530
REGISTRANDO EL SERVIDOR 532
IMPLEMENTACIÓN DE INTERFACES 534
EL HUEVO, LA GALLINA Y LAS FÁBRICAS DE CLASES 536
IMPLEMENTANDO LA FÁBRICA DE CLASES 538
28. AUTOMATIZACIÓN OLE: CONTROLADORES 541
¿POR QUÉ EXISTE LA AUTOMATIZACIÓN OLE? 541
CONTROLADORES DE AUTOMATIZACIÓN CON VARIANTES 543
PROPIEDADES OLE Y PARÁMETROS POR NOMBRE 544
INTERFACES DUALES 545
BIBLIOTECAS DE TIPOS 546
IMPORTACIÓN DE BIBLIOTECAS DE TIPOS 547
EVENTOS 549
ESCUCHANDO A WORD 552
29. AUTOMATIZACIÓN OLE: SERVIDORES 557
INFORMES AUTOMATIZADOS 557
EL OBJETO DE AUTOMATIZACIÓN 559
LA PARTE CLIENTE 563
DECLARANDO UNA INTERFAZ COMÚN 564
MODELOS DE INSTANCIACIÓN 566
MODELOS DE CONCURRENCIA 568
UN SERVIDOR DE BLOQUEOS 570
LA IMPLEMENTACIÓN DE LA LISTA DE BLOQUEOS 572
Indice 13
CONTROL DE CONCURRENCIA 574
PONIENDO A PRUEBA EL SERVIDOR 577
30. MIDAS 579
¿QUÉ ES MIDAS? 579
CUÁNDO UTILIZAR Y CUÁNDO NO UTILIZAR MIDAS 581
MIDAS Y LAS BASES DE DATOS DE ESCRITORIO 583
MÓDULOS DE DATOS REMOTOS 584
PROVEEDORES 587
SERVIDORES REMOTOS Y CONJUNTOS DE DATOS CLIENTES 589
GRABACIÓN DE DATOS 591
RESOLUCIÓN 594
CONTROL DE ERRORES DURANTE LA RESOLUCIÓN 596
RECONCILIACIÓN 599
RELACIONES MASTER/DETAIL Y TABLAS ANIDADAS 601
ENVÍO DE PARÁMETROS 601
EXTENDIENDO LA INTERFAZ DEL SERVIDOR 602
ALGUIEN LLAMA A MI PUERTA 604
LA METÁFORA DEL MALETÍN 606
TIPOS DE CONEXIÓN 606
BALANCE DE CARGA SIMPLE 609
INTERFACES DUALES EN MIDAS 610
COGE EL DINERO Y CORRE: TRABAJO SIN CONEXIÓN 611
31. SERVIDORES DE INTERNET 617
EL MODELO DE INTERACCIÓN EN LA WEB 617
APRENDA HTML EN 14 MINUTOS 618
EXTENSIONES DEL SERVIDOR Y PÁGINAS DINÁMICAS 620
¿QUÉ NECESITO PARA ESTE SEGUIR LOS EJEMPLOS? 622
MÓDULOS WEB 623
ACCIONES 626
RECUPERACIÓN DE PARÁMETROS 628
GENERADORES DE CONTENIDO 629
GENERADORES DE TABLAS 631
MANTENIMIENTO DE LA INFORMACIÓN DE ESTADO 632
¿LE APETECE UNA GALLETA? 634
UN SIMPLE NAVEGADOR 635
AL OTRO LADO DE LA LÍNEA... 639
ACTIVEFORMS: FORMULARIOS EN LA WEB 640
14 La Cara Oculta de C++ Builder
LEFTOVERTURE 645
32. IMPRESIÓN DE INFORMES CON QUICKREPORT 647
LA HISTORIA DEL PRODUCTO 647
LA FILOSOFÍA DEL PRODUCTO 648
PLANTILLAS Y EXPERTOS PARA QUICKREPORT 649
EL CORAZÓN DE UN INFORME 650
LAS BANDAS 652
EL EVENTO BEFOREPRINT 654
COMPONENTES DE IMPRESIÓN 655
EL EVALUADOR DE EXPRESIONES 656
UTILIZANDO GRUPOS 657
ELIMINANDO DUPLICADOS 659
INFORMES MASTER/DETAIL 661
INFORMES COMPUESTOS 662
PREVISUALIZACIÓN A LA MEDIDA 663
LISTADOS AL VUELO 665
ENVIANDO CÓDIGOS BINARIOS A UNA IMPRESORA 667
33. ANÁLISIS GRÁFICO 671
GRÁFICOS Y BIORRITMOS 671
EL COMPONENTE TDBCHART 675
COMPONENTES NO VISUALES DE DECISION CUBE 677
REJILLAS Y GRÁFICOS DE DECISIÓN 679
USO Y ABUSO DE DECISION CUBE 681
MODIFICANDO EL MAPA DE DIMENSIONES 682
34. DESCENSO A LOS ABISMOS 685
INICIALIZACIÓN Y FINALIZACIÓN DEL BDE 685
EL CONTROL DE ERRORES 687
SESIONES Y CONEXIONES A BASES DE DATOS 688
CREACIÓN DE TABLAS 690
REESTRUCTURACIÓN 693
ELIMINACIÓN FÍSICA DE REGISTROS BORRADOS 695
CURSORES 696
UN EJEMPLO DE ITERACIÓN 698
PROPIEDADES 700
LAS FUNCIONES DE RESPUESTA DEL BDE702
35. CREACIÓN DE INSTALACIONES 705
LOS PROYECTOS DE INSTALLSHIELD EXPRESS 705
LA PRESENTACIÓN DE LA INSTALACIÓN 707
Indice 15
LAS MACROS DE DIRECTORIOS 708
GRUPOS Y COMPONENTES 709
INSTALANDO EL BDE Y LOS SQL LINKS 711
CONFIGURACIÓN ADICIONAL DEL BDE 713
INSTALACIÓN DE PAQUETES 713
INTERACCIÓN CON EL USUARIO 714
LAS CLAVES DEL REGISTRO DE WINDOWS 716
CÓMO SE REGISTRAN LOS COMPONENTES ACTIVEX 717
ICONOS Y CARPETAS 718
GENERANDO Y PROBANDO LA INSTALACIÓN 719
LA VERSIÓN COMPLETA DE INSTALLSHIELD EXPRESS 720
LAS EXTENSIONES DE INSTALLSHIELD EXPRESS 721
36. EJEMPLOS: LIBRETAS DE AHORRO 723
DESCRIPCIÓN DEL MODELO DE DATOS 723
LIBRETAS DE AHORRO EN MS SQL SERVER 729
AHORA, EN ORACLE 733
EL MÓDULO DE DATOS 736
TRANSACCIONES EXPLÍCITAS 739
GESTIÓN DE LIBRETAS Y OPERACIONES 740
ENTRADA DE APUNTES 742
LA VENTANA PRINCIPAL 744
CORRIGIENDO EL IMPORTE DE UN APUNTE 746
37. EJEMPLOS: UN SERVIDOR DE INTERNET 749
BÚSQUEDA DE PRODUCTOS 749
EL MOTOR DE BÚSQUEDAS 751
CREANDO LA EXTENSIÓN WEB 754
GENERANDO LA TABLA DE RESULTADOS 756
DOCUMENTOS HTML Y SUSTITUCIÓN DE ETIQUETAS 757
RESPONDIENDO A LAS ACCIONES 759
APENDICE: EXCEPCIONES 761
SISTEMAS DE CONTROL DE ERRORES 761
CONTRATOS INCUMPLIDOS 762
CÓMO SE INDICA UN ERROR 763
LA EJECUCIÓN DEL PROGRAMA FLUYE EN DOS DIMENSIONES 764
PAGAMOS NUESTRAS DEUDAS 765
LA DESTRUCCIÓN DE OBJETOS DINÁMICOS 766
EL BLOQUE DE PROTECCIÓN DE RECURSOS 768
CÓMO TRANQUILIZAR A UN PROGRAMA ASUSTADO 770
EJEMPLOS DE CAPTURA DE EXCEPCIONES 771
CAPTURANDO EL OBJETO DE EXCEPCIÓN 772
16 La Cara Oculta de C++ Builder
CAPTURA Y PROPAGACIÓN DE EXCEPCIONES DE LA VCL 773
DISTINGUIR EL TIPO DE EXCEPCIÓN 773
LAS TRES REGLAS DE MARTEENS 774
CICLO DE MENSAJES Y MANEJO DE EXCEPCIONES 775
EXCEPCIONES A LA TERCERA REGLA DE MARTEENS 777
EL EVENTO ONEXCEPTION 778
LA EXCEPCIÓN SILENCIOSA 781
CONSTRUCTORES Y EXCEPCIONES 782
INDICE ALFABETICO 787
Prólogo del AutorPrólogo del Autor
“The day must come - if the world last long enough -” said Arthur,
“when every possible tune will have been composed - every possible pun perpetrated ...
and, worse than that, every possible book written! For the number of words is finite.”
“It’ll make very little difference to the authors,” I suggested. “Instead of saying ‘what book shall I
write?’ an author will ask himself ‘which book shall I write?’ A mere verbal distinction!”
Lady Muriel gave me an approving smile. “But lunatics would always write new books, surely?”
she went on. “They couldn’t write the sane books over again!”
 Lewis Carroll - Sylvie and Bruno Concluded
O CREO EN LAS ENCICLOPEDIAS; de hecho, nunca he podido terminar de
leer alguna. Sin embargo, cada vez que hojeo un nuevo libro sobre C++
Builder o Delphi me da la impresión de que el autor ha intentado preci-
samente escribir una enciclopedia; lástima que, en la mayoría de los casos, el volumen
del libro se limita a lo sumo a un tomo de no más de 1000 páginas.
Este libro no pretende ni puede abarcar todos los temas relacionados con la pro-
gramación en C++ Builder; su objetivo concreto son LAS TÉCNICAS DE PROGRAMA-
CIÓN DE BASES DE DATOS UTILIZANDO C++ BUILDER, con énfasis especial en el
desarrollo de aplicaciones cliente/servidor y de múltiples capas, tarea para la que los
entornos de programación de Borland están particularmente bien preparados.
Por lo tanto, asumiré cierta familiaridad del lector con C++, bastante común entre
los programadores de hoy día; sería impensable intentar suplantar a clásicos de tal
envergadura como “El Lenguaje de Programación C++” del creador del lenguaje, Bjarne
Stroustrup.
Contenido del libro
El libro se divide en cinco partes, que son las siguientes:
• La Parte 1 – “El lenguaje SQL” – ofrece una extensa presentación de los
elementos de SQL, tanto en lo referente a las instrucciones básicas del estándar
ANSI 92, como en todo lo relacionado con la programación del lado del
servidor: el lenguaje de triggers y procedimientos almacenados. En este último
aspecto, los conceptos se presentan utilizando la sintaxis de InterBase, el
servidor SQL de Borland. Posteriormente, presentamos por separado las
características distintivas de los tres sistemas cliente/servidor más utilizados hoy:
Microsoft SQL Server, IBM DB2 Universal Database y Oracle.
N
18 La Cara Oculta de C++ Builder
• La Parte 2 – “Navegación y búsqueda” – describe las facilidades básicas que
ofrecen los componentes VCL incluidos en C++ Builder para que
representemos los conjuntos de datos con los que vamos a trabajar y nos
desplacemos por los registros que los componen. Esta parte se encarga también
de presentar la filosofía de utilización de controles visuales con conexión a datos
(data-aware controls) y de mostrar ejemplos de cómo obtener interfaces de usuario
atractivas para mostrar la información. Para concluir esta parte, “Comunicación
cliente/servidor” describe las técnicas generales que deben tenerse en cuenta al
interactuar con bases de datos remotas; en este capítulo mostramos la
inconsistencia de varios mitos de amplia difusión entre la comunidad de
programadores.
• En la Parte 3 – “Actualizaciones y concurrencia” – se describen en detalle las
posibilidades que ofrece C++ Builder a la hora de actualizar el contenido de
nuestras bases de datos. En estos capítulos se hace especial énfasis en todo lo
relacionado con la optimización del acceso concurrente a las bases de datos, de
forma que sea posible minimizar la contención entre aplicaciones que se ejecuten
simultáneamente desde diferentes clientes, y se describen las posibilidades que
ofrece el Motor de Datos de Borland (Borland Database Engine - BDE) para la
implementación de transacciones y las ventajas y limitaciones en este sentido de
los diferentes sistemas SQL con los que el BDE puede comunicarse.
• La Parte 4 – “Programación Distribuida” – es, técnicamente hablando, la más
compleja del libro. En esta parte describiré inicialmente en detalle las posibili-
dades del componente TClientDataSet, la clase sobre la que se basa la programa-
ción de clientes delgados para el desarrollo de aplicaciones de múltiples capas en
C++ Builder. Luego introduciré los conceptos fundamentales del Modelo de
Objetos Componentes (COM) de Microsoft, la base sobre la que se apoya la
programación de servidores de capa intermedia; inmediatamente después, un
amplio capítulo describe en detalle las posibilidades de la tecnología que Borland
ha llamado MIDAS y se presentan ejemplos de aplicaciones de tres capas. Pero
todavía le quedará mucho más por ver en esta parte: el siguiente capítulo muestra
cómo utilizar los asistentes y componentes que incluye C++ Builder para crear
extensiones de servidores de Internet que construyan dinámicamente páginas
HTML a partir del contenido de bases de datos.
• En la Parte 5, que he denominado “Leftoverture”1, se aglutina toda una serie de
capítulos que en principio no tienen una conexión directa entre sí. Aquí
encontrará todo lo relacionado con cómo utilizar QuickReport, la herramienta de
generación de informes que se incluye en C++ Builder, cómo incluir en sus apli-
caciones tablas de análisis multidimensional de datos a partir de los componentes
Decision Cube, o cómo generar instalaciones con InstallShield Express for C++
 
1 “Leftoverture” es el nombre de un álbum producido en 1976 por Kansas. El nombre es
una combinación de las palabras “leftover” (remanente, residuo) y “overture” (obertura). La
pieza clave del álbum fue compuesta mezclando trozos de otras canciones que habían sido
descartadas por el grupo.
Prólogo del Autor 19
Builder. Los dos últimos capítulos presentan dos ejemplos completos de
aplicaciones, cuyo código fuente podrá utilizar como material de estudio.
Mi propósito es que éste sea un libro vivo, que crezca a la vista de todos. Así intento
evitar la incómoda sensación que queda al entregar los ficheros a la imprenta de que
te has olvidado de mencionar algo importante. ¿Cómo crece este libro? Visite mi
página Web, en www.marteens.com,donde podrá encontrar trucos y artículos
técnicos que sirven de extensión a estas páginas.
Agradecimientos
Como siempre, los protagonistas de todos mis libros son todos los programadores
que tengo el gusto de conocer y trabajar en alguna medida con ellos. Lo poco de
original que hay en estas páginas casi siempre ha surgido de problemas reales que nos
hemos vistos obligados a enfrentar en conjunto. A veces la solución ha sido nuestra,
pero muchas otras nos han salvado la vida tantas personas que nos sería imposible
intentar mencionarlas a todas. Y están los cientos de programadores que, a través del
correo electrónico, nos han animado a seguir adelante. Pero la principal fuerza que ha
movido este proyecto ha sido Dave. Sin él, este libro no estaría ahora en sus manos.
Como no me gusta ponerme solemne, quiero concluir agradeciendo a Dios, al Dia-
blo o a la Selección Natural (no estoy seguro), por haberme colocado en el cráneo
esa neurona sarcástica que impide que tome en serio a algo o a alguien, incluyén-
dome a mí mismo. El día que me falle ... quizás me dedique a escribir sobre la capa
de ozono.
Ian Marteens
Madrid, Junio de 1999
 El Lenguaje SQL
• Sistemas de bases de datos
• Breve introducción a SQL
• Consultas y modificaciones
• Procedimientos almacenados y triggers
• Transacciones
• Microsoft SQL Server
• Oracle
• DB2 Universal Database
• El Motor de Datos de Borland
�
Parte
Capítulo
1
Sistemas de bases de datosSistemas de bases de datos
STE ES EL MOMENTO APROPIADO para presentar a los protagonistas de este
drama: los sistemas de gestión de bases de datos con los que intentaremos
trabajar. En mi trabajo de consultor, la primera pregunta que escucho, y la
más frecuente, es en qué lenguaje debe realizarse determinado proyecto. Enfoque
equivocado. La mayoría de los proyectos que llegan a mis manos son aplicaciones
para redes de área local, y os garantizo que la elección del lenguaje es asunto relati-
vamente secundario para el éxito de las mismas; por supuesto, siempre recomiendo
algún lenguaje “decente”, sin limitaciones intrínsecas, como C++ Builder o Delphi.
La primera pregunta debería ser: ¿qué sistema de bases de datos es el más apropiado
a mis necesidades?
En este capítulo recordaremos los principios básicos de los sistemas de bases de
datos relacionales, y haremos una rápida introducción a algunos sistemas concretos
con los que C++ Builder puede trabajar de modo directo. La explicación relativa a
los sistemas de bases de datos locales será más detallada que la de los sistemas
cliente/servidor, pues las características de estos últimos (implementación de índices,
integridad referencial, seguridad) irán siendo desveladas a lo largo del libro.
Acerca del acceso transparente a bases de datos
¿Pero acaso C++ Builder no ofrece cierta transparencia con respecto al formato de
los datos con los que estamos trabajando? Pues sí, sobre todo para los formatos
soportados por el Motor de Bases de Datos de Borland (BDE), que estudiaremos en
el capítulo correspondiente. Sin embargo, esta transparencia no es total, incluso den-
tro de las bases de datos accesibles mediante el BDE. Hay una primera gran división
entre las bases de datos locales y los denominados sistemas SQL. Luego vienen las
distintas posibilidades expresivas de los formatos; incluso las bases de datos SQL,
que son las más parecidas entre sí, se diferencian en las operaciones que permiten o
no. Si usted está dispuesto a utilizar el mínimo común denominador entre todas ellas,
su aplicación puede que funcione sin incidentes sobre determinado rango de posibles
sistemas ... pero le aseguro que del mismo modo desperdiciará recursos de progra-
E
24 La Cara Oculta de C++ Builder
mación y diseño que le habrían permitido terminar mucho antes la aplicación, y que
ésta se ejecutara más eficientemente.
Bases de datos relacionales
Por supuesto, estimado amigo, todos los sistemas de bases de datos con los que va-
mos a trabajar en C++ Builder serán sistemas relacionales. Por desgracia. ¿Cómo que
por desgracia, hereje insensato? Para saber qué nos estamos perdiendo con los siste-
mas relacionales tendríamos que conocer las alternativas. Necesitaremos, lo lamento,
un poco de vieja Historia.
En el principio no había ordenadores, claro está. Pero cuando los hubo, y después de
largos años de almacenar información “plana” en grandes cintas magnéticas o perfo-
radas, los informáticos comenzaron a organizar sus datos en dos tipos de modelos: el
modelo jerárquico y el modelo de redes. El modelo jerárquico era un invento digno
de un oficial prusiano. Los diferentes tipos de información se clasificaban en forma
de árbol. En determinada base de datos, por ejemplo, la raíz de este árbol eran los
registros de empresas. Cada empresa almacenaría los datos de un conjunto de de-
partamentos, estos últimos serían responsables de guardar los datos de sus emplea-
dos, y así sucesivamente. Además del conjunto de departamentos, una empresa po-
dría ser propietaria de otro conjunto de registros, como bienes inmuebles o algo así.
El problema, como es fácil de imaginar, es que el mundo real no se adapta fácilmente
a este tipo de organización. Por lo tanto, a este modelo de datos se le añaden chapu-
zas tales como “registros virtuales” que son, en el fondo, una forma primitiva de
punteros entre registros.
El modelo de redes era más flexible. Un registro podía contener un conjunto de
otros registros. Y cada uno de estos registros podía pertenecer a más de un conjunto.
La implementación más frecuente de esta característica se realizaba mediante punte-
ros. El sistema más famoso que seguía este modelo, curiosamente, fue comprado por
cierta compañía tristemente conocida por hacerse con sistemas de bases de datos
para convertirlos en historia... No, no es esa Compañía en la que estáis pensando... sí,
esa Otra...
Vale, el modelo jerárquico no era muy completo, pero el modelo de redes era razo-
nablemente bueno. ¿Qué pasó con ellos, entonces? ¿Por qué se extinguieron en el
Jurásico? Básicamente, porque eran sistemas navegacionales. Para obtener cualquier
información había que tener una idea muy clara de cómo estaban organizados los
datos. Pero lo más molesto era que no existían herramientas sencillas que permitieran
realizar consultas arbitrarias en una base de datos. Si el presidente de la compañía
quería saber cuántos clientes del área del Pacífico bebían Coca-Cola a las cinco de la
tarde en vez de té, tenía que llamar al programador para que le desarrollara una pe-
queña aplicación.
Sistemas de bases de datos 25
Entonces apareció Mr. Codd, un matemático de IBM. No inventó el concepto de
registro, que ya existía hacía tiempo. Pero se dio cuenta que si obligaba a que todos
los campos de los registros fueran campos simples (es decir, que no fueran punteros,
vectores o subregistros) podía diseñarse un grácil sistema matemático que permitía
descomponer información acerca de objetos complejos en estos registros planos, con
la seguridad de poder restaurar la información original más adelante, con la ayuda de
operaciones algebraicas. Lo más importante: casi cualquier tipo de información podía
descomponerse de este modo, así que el modelo era lo suficientemente general. A la
teoría matemática que desarrolló se le conoce con el nombre de álgebra relacional, y es
la base de nuestro conocido lenguaje SQL y del quizás menos popular Query By Ex-
ample, o QBE. De este modo, el directivo del párrafo anterior podía sentarse frente a
una consola, teclear un par de instrucciones en SQL y ahorrarse el pago de las horas
extras del programador2.
Tomemos como ejemplo una base de datos que almacene datos acerca de Departa-
mentos y sus Empleados. Los modelos jerárquicos y de redes la representarían con
un diagrama similar al siguiente:
Departamentos
Empleados
Investigación &
Desarrollo
Ventas
A. Einstein P. Dirac Nelson R. Alfred C.H. Ford
$1.000.000
$10.000
Como puede verse, los punteros son parte ineludible del modelo. ¿Hay algún mate-
mático que sepa cómo comportarsefrente a un puntero? Al parecer, no los había en
los 60 y 70. Sin embargo, los datos anteriores pueden expresarse, en el modelo rela-
cional, mediante dos conjuntos uniformes de registros y sin utilizar punteros, al me-
nos de forma explícita. De esta manera, es factible analizar matemáticamente los
datos, y efectuar operaciones algebraicas sobre los mismos:
DEPARTAMENTOS EMPLEADOS
Codigo Nombre Presupuesto Dpto Nombre
I+D Investigación y Desarrollo $10.000 I+D A. Einstein
V Ventas $1.000.000 I+D P. Dirac
V Nelson R.
V Henri F.
V Alfred C.
¡Mira, mamá, sin punteros! Departamentos y Empleados son tablas, aunque matemática-
mente se les denomina relaciones. A los registros de estas tablas se les llama filas, para
 
2 Aunque personalmente no conozco a ningún individuo con alfiler de corbata y BMW que
sepa SQL, no cabe duda de que debe existir alguno por ahí.
26 La Cara Oculta de C++ Builder
hacer rabiar a los matemáticos que les llaman tuplas. Y para no desentonar, Codigo,
Nombre y Presupuesto son columnas para unos, mientras que para los otros son campos.
¡Qué más da! Ah, la colección de tablas o relaciones es lo que se conoce como base de
datos.
Las personas inteligentes (como usted y como yo) se dan cuenta enseguida de que en
realidad no hemos eliminado los punteros, sino que los hemos disfrazado. Existe un
vínculo3 entre los campos Código y Dpto que es el sustituto de los punteros. Pero
cuando se representan los datos de esta manera, es más fácil operar con ellos mate-
máticamente. Note, por ejemplo, que para ilustrar los modelos anteriores necesité un
dibujo, mientras que una vulgar tabla de mi procesador de texto me ha bastado en el
segundo caso. Bueno, en realidad han sido dos tablas.
¿Me deja el lector que resuma en un par de frases lo que lograba Codd con su mo-
delo relacional? Codd apuntaba su pistola de rayos desintegradores a cualquier objeto
que se ponía a tiro, incluyendo a su perro, y lo reducía a cenizas atómicas. Después,
con un elegante par de operaciones matemáticas, podía resucitar al animalito, si antes
el viento no barría sus restos de la alfombra.
Información semántica = restricciones
Todo lo que he escrito antes le puede sonar al lector como un disco rayado de tanto
escucharlo. Sin embargo, gran parte de los programadores que se inician en C++
Builder solamente han llegado a asimilar esta parte básica del modelo relacional, y
presentan lagunas aterradoras en el resto de las características del modelo, como
veremos dentro de poco. ¿Qué le falta a las ideas anteriores para que sean completa-
mente prácticas y funcionales? Esencialmente, información semántica: algo que nos
impida o haga improbable colocar la cabeza del perro donde va la cola, o viceversa
(el perro de una vecina mía da esa impresión).
Casi siempre, esta información semántica se expresa mediante restricciones a los
valores que pueden tomar los datos de una tabla. Las restricciones más sencillas tie-
nen que ver con el tipo de valores que puede albergar una columna. Por ejemplo, la
columna Presupuesto solamente admite valores enteros. Pero no cualquier valor entero:
tienen que ser valores positivos. A este tipo de verificaciones se les conoce como
restricciones de dominio.
El nivel siguiente lo conforman las restricciones que pueden verificarse analizando
los valores de cada fila de forma independiente. Estas no tienen un nombre especial.
 
3 Observe con qué exquisito cuidado he evitado aquí la palabra relación. En inglés existen dos
palabras diferentes: relation y relationship. Pero el equivalente más cercano a esta última sería
algo así como relacionalidad, y eso suena peor que un párrafo del BOE.
Sistemas de bases de datos 27
En el ejemplo de los departamentos y los empleados, tal como lo hemos presentado,
no hay restricciones de este tipo. Pero nos podemos inventar una, que deben satisfa-
cer los registros de empleados:
Dpto <> "I+D" or Especialidad <> "Psiquiatría"
Es decir, que no pueden trabajar psiquiatras en Investigación y Desarrollo (termina-
rían igual de locos). Lo más importante de todo lo que he explicado en esta sección
es que las restricciones más sencillas pueden expresarse mediante elegantes fórmulas
matemáticas que utilizan los nombres de las columnas, o campos, como variables.
Restricciones de unicidad y claves primarias
Los tipos de restricciones siguen complicándose. Ahora se trata de realizar verifica-
ciones que afectan los valores almacenados en varias filas. Las más importantes de
estas validaciones son las denominadas restricciones de unicidad. Son muy fáciles de ex-
plicar en la teoría. Por ejemplo, no pueden haber dos filas en la tabla de departa-
mentos con el mismo valor en la columna Codigo. Abusando del lenguaje, se dice que
“la columna Codigo es única”.
En el caso de la tabla de departamentos, resulta que también existe una restricción de
unicidad sobre la columna Nombre. Y no pasa nada. Sin embargo, quiero que el lector
pueda distinguir sin problemas entre estas dos diferentes situaciones:
1. (Situación real) Hay una restricción de unicidad sobre Codigo y otra restricción de
unicidad sobre Nombre.
2. (Situación ficticia) Hay una restricción de unicidad sobre la combinación de co-
lumnas Codigo y Nombre.
Esta segunda restricción posible es más relajada que la combinación real de dos res-
tricciones (compruébelo). La unicidad de una combinación de columnas puede vi-
sualizarse de manera sencilla: si se “recortan” de la tabla las columnas que no partici-
pan en la restricción, no deben quedar registros duplicados después de esta opera-
ción. Por ejemplo, en la tabla de empleados, la combinación Dpto y Nombre es única.
La mayoría de los sistemas de bases de datos se apoyan en índices para hacer cumplir
las restricciones de unicidad. Estos índices se crean automáticamente tomando como
base a la columna o combinación de columnas que deben satisfacer estas condicio-
nes. Antes de insertar un nuevo registro, y antes de modificar una columna de este
tipo, se busca dentro del índice correspondiente para ver si se va a generar un valor
duplicado. En tal caso se aborta la operación.
28 La Cara Oculta de C++ Builder
Así que una tabla puede tener una o varias restricciones de unicidad (o ninguna).
Escoja una de ellas y desígnela como clave primaria. ¿Cómo, de forma arbitraria? Casi:
se supone que la clave primaria identifica unívocamente y de forma algo misteriosa la
más recóndita esencia de los registros de una tabla. Pero para esto vale lo mismo
cualquier otra restricción de unicidad, y en programación no vale recurrir al misti-
cismo. Hay quienes justifican la elección de la clave primaria entre todas las restric-
ciones de unicidad en relación con la integridad referencial, que estudiaremos en la
próxima sección. Esto tampoco es una justificación, como veremos en breve. En
definitiva, que todas las restricciones de unicidad son iguales, aunque algunas son
más iguales que otras.
¿Quiere saber la verdad? He jugado con trampa en el párrafo anterior. Esa esencia
misteriosa del registro no es más que un mecanismo utilizado por el modelo relacio-
nal para sustituir a los desterrados punteros. Podréis llamarlo identidad del registro, o
cualquier otro nombre rimbombante, pero no es más que una forma de disfrazar un
puntero, y muy poco eficiente, por cierto. Observe la tabla de departamentos: entre
el código y el nombre, ¿cuál columna elegiría como clave primaria? Por supuesto que
el código, pues es el tipo de datos que menos espacio ocupa, y cuando tengamos el
código en la mano podremos localizar el registro de forma más rápida que cuando
tengamos el nombre.
De todos modos, hay alguien que aprovecha inteligentemente la existencia de claves
primarias: el Motor de Datos de Borland. De hecho, estas claves primarias son la
forma en que el Motor de Datos puede simular el concepto de registro activo en una
tabla SQL. Pero tendremos que esperar un poco para desentrañareste ingenioso
mecanismo.
Integridad referencial
Este tipo de restricción es aún más complicada, y se presenta en la columna Dpto de
la tabla de empleados. Es evidente que todos los valores de esta columna deben co-
rresponder a valores almacenados en la columna Codigo de la tabla de departamentos.
Siguiendo mi teoría de la conspiración de los punteros encubiertos, esto equivale a
que cada registro de empleado tenga un puntero a un registro de departamento.
Un poco de terminología: a estas restricciones se les denomina integridad referencial, o
referential integrity. También se dice que la columna Dpto de Empleados es una clave ex-
terna de esta tabla, o foreign key, en el idioma de Henry Morgan. Podemos llamar tabla
dependiente, o tabla de detalles, a la tabla que contiene la clave externa, y tabla
maestra a la otra. En el ejemplo que consideramos, la clave externa consiste en una
sola columna, pero en el caso general podemos tener claves externas compuestas.
Sistemas de bases de datos 29
Como es fácil de ver, las columnas de la tabla maestra a las que se hace referencia en
una integridad referencial deben satisfacer una restricción de unicidad. En la teoría
original, estas columnas deberían ser la clave primaria, pero la mayoría de los siste-
mas relacionales actuales admiten cualquiera de las combinaciones de columnas úni-
cas definidas.
Cuando se establece una relación de integridad referencial, la tabla dependiente
asume responsabilidades:
• No se puede insertar una nueva fila con un valor en las columnas de la clave
externa que no se encuentre en la tabla maestra.
• No se puede modificar la clave externa en una fila existente con un valor que no
exista en la tabla maestra.
Pero también la tabla maestra tiene su parte de responsabilidad en el contrato, que se
manifiesta cuando alguien intenta eliminar una de sus filas, o modificar el valor de su
clave primaria. En las modificaciones, en general, pueden desearse dos tipos diferen-
tes de comportamiento:
• Se prohibe la modificación de la clave primaria de un registro que tenga filas de
detalles asociadas.
• Alternativamente, la modificación de la clave se propaga a las tablas depen-
dientes.
Si se trata de un borrado, son tres los comportamientos posibles:
• Prohibir el borrado, si existen filas dependientes del registro.
• Borrar también las filas dependientes.
• Permitir el borrado y, en vez de borrar las filas dependientes, romper el vínculo
asociando a la clave externa un valor por omisión, que en SQL casi siempre es el
valor nulo (ver el siguiente capítulo).
La forma más directa de implementar las verificaciones de integridad referencial es
utilizar índices. Las responsabilidades de la tabla dependiente se resuelven compro-
bando la existencia del valor a insertar o a modificar en el índice asociado a la restric-
ción de unicidad definida en la tabla maestra. Las responsabilidades de la tabla maes-
tra se resuelven generalmente mediante índices definidos sobre la tabla de detalles.
¿Qué tiene de malo el modelo relacional?
El modelo relacional funciona. Además, funciona razonablemente bien. Pero como
he tratado de explicar a lo largo de las secciones anteriores, en determinados aspectos
30 La Cara Oculta de C++ Builder
significa un retroceso en comparación con modelos de datos anteriores. Me refiero a
lo artificioso del proceso de eliminar los punteros implícitos de forma natural en el
modelo semántico a representar. Esto se refleja también en la eficiencia de las opera-
ciones. Supongamos que tenemos un registro de empleado en nuestras manos y que-
remos saber el nombre del departamento al que pertenece. Bien, pues tenemos que
buscar el código de departamento dentro de un índice para después localizar física-
mente el registro del departamento correspondiente y leer su nombre. Al menos, un
par de accesos al disco duro. Compare con la sencillez de buscar directamente el
registro de departamento dado su puntero (existen implementaciones eficientes del
concepto de puntero cuando se trabaja con datos persistentes).
En este momento, las investigaciones de vanguardia se centran en las bases de datos
orientadas a objetos, que retoman algunos conceptos del modelo de redes y del pro-
pio modelo relacional. Desde la década de los 70, la investigación matemática ha
avanzado lo suficiente como para disponer de potentes lenguajes de interrogación
sobre bases de datos arbitrarias. No quiero entrar a analizar el porqué no se ha aca-
bado de imponer el modelo orientado a objetos sobre el relacional, pues en esto
influyen tanto factores técnicos como comerciales. Pero es bueno que el lector sepa
qué puede pasar en un futuro cercano.
Es sumamente significativo que la principal ventaja del modelo relacional, la posibili-
dad de realizar consultas ad hoc estuviera fuera del alcance del modelo “relacional”
más popular a lo largo de los ochenta: dBase, y sus secuelas Clipper y FoxPro.
Cuando escucho elogios sobre Clipper por parte de programadores que hicieron
carrera con este lenguaje, pienso con tristeza que los elogios los merecen los propios
programadores que pudieron realizar software funcional con herramientas tan primi-
tivas. Mi aplauso para ellos; en ningún caso para el lenguaje. Y mi consejo de que
abandonen el viejo buque (y las malas costumbres aprendidas durante la travesía)
antes de que termine de hundirse.
Ilustración 1 El perro de Codd
Sistemas de bases de datos 31
Y a todas estas, ¿qué pasó con la mascota de Mr. Codd? Lo inevitable: murió como
consecuencia de un experimento fallido. Sin embargo, Brahma se apiadó de él, y
reencarnó al año en un chico que, con el tiempo, se ha convertido en un exitoso pro-
gramador afincado en el sur de la Florida. Al verlo, nadie pensaría que fue un perro
en su vida anterior, de no ser por la manía que tiene de rascarse periódicamente la
oreja. No obstante, por haber destrozado la tapicería del sofá de su dueño y orinarse
un par de veces en la alfombra del salón, fue condenado a programar dos largos años
en Visual Basic, hasta que C++ Builder (¿o fue Delphi?) llegó a su vida y se convirtió
en un hombre feliz.
Bases de datos locales y servidores SQL
Basta ya de teoría, y veamos los ingredientes con que contamos para cocinar apli-
caciones de bases de datos. La primera gran división entre los sistemas de bases de
datos existentes se produce entre los sistemas locales, o de escritorio, y las bases de
datos SQL, o cliente/servidor.
A los sistemas de bases de datos locales se les llama de este modo porque comenza-
ron su existencia como soluciones baratas para un solo usuario, ejecutándose en un
solo ordenador. Sin embargo, no es un nombre muy apropiado, porque más adelante
estos sistemas crecieron para permitir su explotación en red. Tampoco es adecuado
clasificarlas como “lo que queda después de quitar las bases de datos SQL”. Es cierto
que en sus inicios ninguna de estas bases de datos soportaba un lenguaje de consultas
decente, pero esta situación también ha cambiado.
En definitiva, ¿cuál es la esencia de las bases de datos de escritorio? Pues el hecho de
que la programación usual con las mismas se realiza en una sola capa. Todos estos
sistemas utilizan como interfaz de aplicaciones un motor de datos que, en la era de la
supremacía de Windows, se implementa como una DLL. En la época de MS-DOS,
en cambio, eran funciones que se enlazaban estáticamente dentro del ejecutable.
Observe el siguiente diagrama, que representa el uso en red de una base de datos “de
escritorio”:
BDE BDE
Aplicación Aplicación
Base de
Datos
32 La Cara Oculta de C++ Builder
Aunque la segunda burbuja dice “BDE”, el Motor de Datos de Borland, sustituya
estas siglas por DAO, y podrá aplicar el diagrama a Access. He representado la apli-
cación y el motor de datos en dos burbujas separadas, pero en realidad, constituyen
un mismo ejecutable. Lo más importante, sin embargo, es que no existe un software
central que sirva de árbitro para el acceso a la base de datos “física”. Es como si las
dos aplicacionesdeambularan a ciegas en un cuarto oscuro, tratando de sentarse en
algún sitio libre. Por supuesto, la única forma que tienen de saberlo es intentar ha-
cerlo y confiar en que no haya nadie debajo.
Debido a esta forma primitiva de resolver las inevitables colisiones, la implementa-
ción de la concurrencia, las transacciones y, en último término, la recuperación des-
pués de fallos, ha sido tradicionalmente el punto débil de las bases de datos de escri-
torio. Si está pensando en decenas o cientos de usuarios atacando simultáneamente a
sus datos, y en ejércitos de extremidades inferiores listas para tropezar con cables,
olvídese de Paradox, dBase y Access, pues necesitará una base de datos
cliente/servidor.
Las bases de datos cliente/servidor, o bases de datos SQL, se caracterizan por utili-
zar al menos dos capas de software, como se aprecia en el siguiente diagrama:
Cliente SQL Cliente SQL
Aplicación Aplicación
Base de
Datos
Servidor SQL
El par aplicación + motor local de datos ya no tiene acceso directo a los ficheros de
la base de datos, pues hay un nuevo actor en el drama: el servidor SQL. He cambiado
el rótulo de la burbuja del motor de datos, y ahora dice “cliente SQL”. Esta es una
denominación genérica. Para las aplicaciones desarrolladas con C++ Builder y el
Motor de Datos de Borland, este cliente consiste en la combinación del BDE pro-
piamente dicho más alguna biblioteca dinámica o DLL suministrada por el fabricante
de la base de datos. En cualquier caso, todas estas bibliotecas se funden junto a la
aplicación dentro de una misma capa de software, compartiendo el mismo espacio de
memoria y procesamiento.
La división entre bases de datos de escritorio y las bases de datos SQL no es una
clasificación tajante, pues se basa en la combinación de una serie de características.
Sistemas de bases de datos 33
Puede que uno de estos días aparezca un sistema que mezcle de otra forma estos ras-
gos definitorios.
Características generales de los sistemas SQL
El hecho de que exista un árbitro en las aplicaciones cliente/servidor hace posible
implementar una gran variedad de técnicas y recursos que están ausentes en la mayo-
ría de los sistemas de bases de datos de escritorio. Por ejemplo, el control de concu-
rrencia se hace más sencillo y fiable, pues el servidor puede llevar la cuenta de qué
clientes están accediendo a qué registros durante todo el tiempo. También es más
fácil implementar transacciones atómicas, esto es, agrupar operaciones de modifi-
cación de forma tal que, o se efectúen todas, o ninguna llegue a tener efecto.
Pero una de las principales características de las bases de datos con las que vamos a
trabajar es la forma peculiar en que “conversan” los clientes con el servidor. Resulta
que estas conversaciones tienen lugar en forma de petición de ejecución de coman-
dos del lenguaje SQL. De aquí el nombre común que reciben estos sistemas. Supon-
gamos que un ordenador necesita leer la tabla de inventario. Recuerde que ahora no
podemos abrir directamente un fichero situado en el servidor. Lo que realmente hace
la estación de trabajo es pedirle al servidor que ejecute la siguiente instrucción SQL:
select * from Inventario order by CodigoProducto asc
El servidor calcula qué registros pertenecen al resultado de la consulta, y todo este
cálculo tiene lugar en la máquina que alberga al propio servidor. Entonces, cada vez
que el usuario de la estación de trabajo se mueve de registro a registro, el cliente SQL
pide a su servidor el siguiente registro mediante la siguiente instrucción:
fetch
Más adelante necesitaremos estudiar cómo se realizan las modificaciones, inserciones,
borrados y búsquedas, pero con esto basta por el momento. Hay una conclusión
importante a la que ya podemos llegar: ¿qué es más rápido, pulsar un botón en la
máquina de bebidas o mandar a un acólito a que vaya por una Coca-Cola? A no ser
que usted sea más vago que yo, preferirá la primera opción. Bien, pues un sistema
SQL es inherentemente más lento que una base de datos local. Antes manipulába-
mos directamente un fichero. Ahora tenemos que pedírselo a alguien, con un proto-
colo y con reglas de cortesía. Ese alguien tiene que entender nuestra petición, es
decir, compilar la instrucción. Luego debe ejecutarla y solamente entonces procederá
a enviarnos el primer registro a través de la red. ¿Está de acuerdo conmigo?
No pasa una semana sin que conozca a alguien que ha desarrollado una aplicación
para bases de datos locales, haya decidido pasarla a un entorno SQL, y haya pensado
34 La Cara Oculta de C++ Builder
que con un par de modificaciones en su aplicación era suficiente. Entonces descubre
que la aplicación se ejecuta con mayor lentitud que antes, cae de rodillas, mira al cielo
y clama: ¿dónde está entonces la ventaja de trabajar con sistemas cliente/servidor?
Está, amigo mío, en la posibilidad de meter código en el servidor, y si fallamos en
hacerlo estaremos desaprovechando las mejores dotes de nuestra base de datos.
Hay dos formas principales de hacerlo: mediante procedimientos almacenados y
mediante triggers. Los primeros son conjuntos de instrucciones que se almacenan
dentro de la propia base de datos. Se activan mediante una petición explícita de un
cliente, pero se ejecutan en el espacio de aplicación del servidor. Por descontado,
estos procedimientos no deben incluir instrucciones de entrada y salida. Cualquier
proceso en lote que no contenga este tipo de instrucciones es candidato a codificarse
como un procedimiento almacenado. ¿La ventaja?, que evitamos que los registros
procesados por el procedimiento tengan que atravesar la barrera del espacio de me-
moria del servidor y viajar a través de la red hasta el cliente.
Los triggers son también secuencias de instrucciones, pero en vez de ser activados
explícitamente, se ejecutan como preludio y coda de las tres operaciones básicas de
actualización de SQL: update, insert y delete. No importa la forma en que estas
tres operaciones se ejecuten, si es a instancias de una aplicación o mediante alguna
herramienta incluida en el propio sistema; los triggers que se hayan programado se
activarán en cualquier caso.
Estos recursos se estudiarán más adelante, cuando exploremos el lenguaje SQL.
El formato Paradox
Comenzaremos nuestra aventura explicando algunas características de los sistemas de
bases de datos de escritorio que pueden utilizarse directamente con C++ Builder. De
estos, mi actual favorito es Paradox. Pongo el adjetivo “actual” porque el nuevo for-
mato de Visual dBase VII comienza a aproximarse a la riqueza expresiva soportada
desde hace mucho por Paradox. Dedicaremos a dBase la siguiente sección.
Paradox no reconoce directamente el concepto de base de datos, sino que administra
tablas en ficheros independientes. Cada tabla se almacena en un conjunto de ficheros,
todos con el mismo nombre, pero con las extensiones que explicamos a continua-
ción:
Extensión Explicación
.db Definición de la tabla y campos de longitud máxima fija
.mb Campos de longitud variable, como los memos y gráficos
.px El índice de la clave primaria
Sistemas de bases de datos 35
Extensión Explicación
.Xnn, .Ynn Indices secundarios
.val Validaciones e integridad referencial
En el fichero .db se almacena una cabecera con la descripción de la tabla, además de
los datos de los registros que corresponden a campos de longitud fija. Este fichero
está estructurado en bloques de idéntico tamaño; se pueden definir bloques de 1, 2,
4, 8, 16 y 32KB. El tamaño de bloque se determina durante la creación de la tabla
mediante el parámetro BLOCK SIZE del controlador de Paradox del BDE (por omi-
sión, 2048 bytes); en el capítulo 16 aprenderemos a gestionar éste y muchos otros
parámetros. El tamaño de bloque influye en la extensión máxima de la tabla, pues
Paradox solamente permite 216 bloques por fichero. Si se utiliza el tamaño de bloque
por omisión tendríamos el siguiente tamaño máximo por fichero de datos:
2048 × 65536 = 211 × 216 = 227 = 27 × 220 = 128MB
Un registro debecaber completamente dentro de un bloque, y si la tabla tiene una
clave primaria (¡recomendable!) deben existir al menos tres registros por bloque; esto
se refiere a los datos de longitud fija del registro, excluyendo campos de texto largos,
de imágenes y binarios. Dentro de cada bloque, los registros se ordenan según su
clave primaria, para agilizar la búsqueda una vez que el bloque ha sido leído en la
caché. Un registro, además, siempre ocupa el mismo espacio dentro del fichero .db,
incluso si contiene campos alfanuméricos que, a diferencia de lo que sucede en
dBase, no se rellenan con blancos hasta ocupar el ancho total del campo.
Paradox permite trabajar con un índice primario por cada tabla y con varios índices
secundarios. Todos estos índices pueden ser mantenidos automáticamente por el
sistema, aunque existe la posibilidad de crear índices secundarios no mantenidos. El
índice primario de la tabla se almacena en el fichero de extensión .px. No es necesa-
rio que una tabla tenga índice primario, pero es altamente ventajoso. Al estar ordena-
dos los registros dentro los bloques de datos, sólo se necesita almacenar en el índice
la clave del primer registro de cada bloque. Esto disminuye considerablemente los
requerimientos de espacio del índice, y acelera las búsquedas.
Es interesante conocer cómo Paradox implementa los índices secundarios. En reali-
dad, cada índice secundario es internamente una tabla, con su propio fichero de da-
tos, de extensión .Xnn, y su índice asociado .Ynn. La numeración de los índices sigue
un esquema sencillo: los dos últimos caracteres de la extensión indican el número del
campo en hexadecimal, si es un índice sobre un solo campo. Si es un índice com-
puesto, se utiliza una pseudo numeración hexadecimal, pero comenzando desde el
“valor” G0 y progresando en forma secuencial. Desde el punto de vista del usuario,
los índices secundarios tienen un nombre asociado. El índice primario, en cambio, no
tiene nombre.
36 La Cara Oculta de C++ Builder
Se permite el uso directo de índices con claves compuestas, formadas por varios
campos. Otras opciones posibles de un índice Paradox son ignorar las mayúsculas y
minúsculas en los campos de cadenas (la opción por omisión), la restricción de claves
únicas y la posibilidad de ordenación en sentido descendente.
Paradox permite la definición de relaciones de integridad referencial. La siguiente
imagen muestra el diálogo de Database Desktop que lo hace posible:
El motor de datos crea automáticamente un índice secundario sobre las columnas de
la tabla dependiente que participan en una restricción de integridad. Si la restricción
está basada en una sola columna, el índice recibe el nombre de la misma. La tabla que
incluyo a continuación describe la implementación en Paradox del comportamiento
de la integridad referencial respecto a actualizaciones en la tabla maestra:
Borrados Modificaciones
Prohibir la operación Sí Sí
Propagar en cascada No Sí
Asignar valor por omisión No -
No se permiten los borrados en cascada. No obstante, este no es un impedimento
significativo, pues dichos borrados pueden implementarse fácilmente en las aplica-
ciones clientes. En cambio, trate el lector de implementar una propagación en cas-
cada de un cambio de clave cuando existe una integridad referencial...
No fue hasta la aparición de la versión 3.0 del BDE, que acompañó a Delphi 2, que
Paradox y dBase contaron con algún tipo de soporte para transacciones. No obs-
tante, este soporte es actualmente muy elemental. Utiliza un undo log, es decir, un
fichero en el que se van grabando las operaciones que deben deshacerse. Si se desco-
necta la máquina durante una de estas transacciones, los cambios aplicados a medias
quedan grabados, y actualmente no hay forma de deshacerlos. La independencia
entre transacciones lanzadas por diferentes procesos es la mínima posible, pues un
Sistemas de bases de datos 37
proceso puede ver los cambios efectuados por otro proceso aunque éste no haya
confirmado aún toda la transacción.
Finalmente, las transacciones locales tienen una limitación importante. La contención
entre procesos está implementada mediante bloqueos. Actualmente Paradox permite
hasta 255 bloqueos por tabla, y dBase solamente 100. De modo que una transacción
en Paradox puede modificar directamente un máximo de 255 registros por tabla.
El formato DBF7
¿Quién no ha tenido que trabajar, en algún momento y de una forma u otra, con los
conocidos ficheros DBF? La popularidad de este formato se desarrolló en paralelo
con la aparición de los PCs y la propagación de MS-DOS. En el principio, era pro-
piedad de una compañía llamada Ashton-Tate. Ashton fue el empresario que compró
el software a su desarrollador, y tenía un loro llamado Tate, ¿o era al revés? Después
a esta empresa le fueron mal las cosas y Borland adquirió sus productos. Aunque
muchos interpretaron esta acción como un reconocimiento a los “méritos” técnicos
de dBase, se trataba en realidad de adquirir otro producto de bases de datos, que en
aquel momento era un perfecto desconocido: InterBase. Hay que advertir que Inter-
Base había sido a su vez comprado por Ashton-Tate a sus desarrolladores originales,
una efímera compañía de nombre Groton Database Systems, cuyas siglas aún perdu-
ran en la extensión por omisión de los ficheros de InterBase: gdb.
El formato DBF es muy sencillo ... y muy malo. Fue diseñado como “la base de da-
tos de los pobres”. Cada tabla, al igual que sucede en Paradox, se representa en un
conjunto de ficheros. El fichero de extensión dbf contiene a la vez la descripción de
los campos y los registros, estos últimos de longitud fija. Los registros se almacenan
de forma secuencial, sin importar las fronteras de bloques y la pérdida de eficiencia
que esto causa. Los tipos de datos originales se representaban en formato ASCII
legible, en vez de utilizar su codificación binaria, más compacta. De este modo, las
fechas se representaban en ocho caracteres, con el formato AAAAMMDD, y un
valor entero de 16 bits ocupaba 40 bits, o 48 si se representaba el signo. Por otra
parte, hasta fechas recientes el único tipo de cadena implementado tenía longitud fija,
obligando a los programadores a usar exhaustivamente la función Trim.
Se pueden utilizar campos de longitud variable, que en principio estuvieron limitados
al tipo texto, o memo. Los valores de estos campos se almacenan en un fichero para-
lelo de extensión dbt. En este fichero los datos sí respetan la frontera de bloque. Por
omisión, el tamaño de estos bloques es de 1024 bytes, pero este parámetro es confi-
gurable. Los índices, por su parte, se almacenan todos en un fichero de extensión
mdx. Aunque, en principio, una tabla puede tener varios ficheros mdx asociados, so-
lamente los índices que se encuentran en el fichero que tiene el mismo nombre que la
38 La Cara Oculta de C++ Builder
tabla se actualizan automáticamente, por lo que en la práctica solamente cuenta este
fichero, denominado índice de producción.
Una de las peculiaridades de dBase es la forma en que se implementan los índices
sobre varias columnas. dBase no tiene índices compuestos, al estilo de Paradox y de
los sistemas SQL. Como alternativa ofrece los índices basados en expresiones: si
queremos un índice compuesto por las columnas Nombre y Apellidos, tenemos que
definir un índice por la expresión Nombre+Apellidos. Puede parecer que ésta es una
opción muy potente, pero en la práctica el uso de los índices sobre expresiones se
reduce a sustituir los índices compuestos de otros sistemas. Además, veremos que
trabajar con estos índices en C++ Builder es bastante penoso. ¿Claves primarias,
integridad referencial? Nada de eso tenía originalmente el formato DBF. Cuesta más
trabajo rediseñar una aplicación escrita en C++ Builder con dBase para que se eje-
cute en un sistema cliente/servidor que si hubiera sido desarrollada para Paradox.
¿Algo a favor de este formato? Las dos cualidades que mencionaré son consecuencia
de la simplicidad de sus ficheros. En primerlugar, las operaciones de actualización
son un poco más rápidas en dBase que en Paradox. Y, lo más importante, al existir
“menos cosas para romperse”, hay más estabilidad en este formato y más tolerancia
respecto a fallos en el sistema operativo.
Con la aparición de Visual dBase 7 junto a la versión 4.50 del BDE, el formato DBF
fue renovado en gran medida. Una de las novedades más importantes es la incorpo-
ración de relaciones de integridad referencial, que incluyen los borrados en cascada,
como se muestra en el siguiente cuadro de diálogo del Administrador de Bases de
Datos de Visual dBase 7:
También se han añadido tipos de datos representados en forma binaria, condiciones
de verificación, que consisten en expresiones lógicas que deben satisfacer siempre las
filas de una tabla, valores por omisión, etc. Lamentablemente, seguimos con los índi-
Sistemas de bases de datos 39
ces de expresiones como sustitutos de los índices compuestos, y el límite de registros
modificados por transacción sigue siendo 100.
Criterios para evaluar un servidor SQL
¿Cómo saber cuál es el sistema de bases de datos cliente/servidor más adecuado para
nuestros objetivos? En esta sección trato de establecer criterios de comparación para
estos sistemas. No hay dos aplicaciones con las mismas necesidades, así que el hecho
de que un sistema no ofrezca determinada opción no lo invalida como la solución
que usted necesita. Recuerde que no siempre más es mejor.
• Plataformas soportadas
¿En qué sistema operativo debe ejecutarse el servidor? La respuesta es impor-
tante por dos razones. La primera: nos da una medida de la flexibilidad que te-
nemos a la hora de seleccionar una configuración de la red. Si vamos a instalar
una aplicación en una empresa que tiene toda su red basada en determinado ser-
vidor con determinado protocolo, no es recomendable que abandonen todo lo
que tienen hecho para que el recién llegado pueda ejecutarse.
En segundo lugar, no todos los sistemas operativos se comportan igual de efi-
cientes actuando como servidores de bases de datos. Esto tiene que ver sobre
todo con la implementación que realiza el SO de la concurrencia. Mi favorito en
este sentido es UNIX: un InterBase, un Oracle, un Informix, ejecutándose sobre
cualquier “sabor” de UNIX (HP-UX, AIX, Solaris).
Puede suceder, por supuesto, que el mantenimiento de la red no esté en manos
de un profesional dedicado a esta área. En tal caso, hay que reconocer que es
mucho más sencillo administrar un Windows NT.
• Soporte de tipos de datos y restricciones
En realidad, casi todos los sistemas SQL actuales tienen tipos de datos que in-
cluyen a los especificados en el estándar de SQL, excepto determinados casos
patológicos. De lo que se trata sobre todo es la implementación de los mismos.
Por ejemplo, no todas los formatos de bases de datos implementan con la misma
eficiencia el tipo VARCHAR, que almacena cadenas de longitud variable. La
longitud máxima es uno de los parámetros que varían, y el formato de represen-
tación: si siempre se asigna un tamaño fijo (el máximo) para estos campos, o si la
longitud total del registro puede variar.
Más importante es el soporte para validaciones declarativas, esto es, verificacio-
nes para las cuales no hay que desarrollar código especial. Dentro de este apar-
tado entran las claves primarias, claves alternativas, relaciones de integridad refe-
rencial, dominios, chequeos a nivel de fila, etc. Un elemento a tener en cuenta,
por ejemplo, es si se permite o no la propagación en cascada de modificaciones
en la tabla maestra de una relación de integridad referencial. En caso positivo,
40 La Cara Oculta de C++ Builder
esto puede ahorrarnos bastante código en triggers y permitirá mejores modelos de
bases de datos.
• Lenguaje de triggers y procedimientos almacenados
Este es uno de los criterios a los que concedo mayor importancia. El éxito de
una aplicación, o un conjunto de aplicaciones, en un entorno C/S depende en
gran medida de la forma en que dividamos la carga de la aplicación entre el ser-
vidor de datos y los clientes. En este punto es donde podemos encontrar mayo-
res diferencias entre los sistemas SQL, pues no hay dos dialectos de este lenguaje
que sean exactamente iguales.
Debemos fijarnos en si el lenguaje permite triggers a nivel de fila o de operación,
o de ambos niveles. Un trigger a nivel de fila se dispara antes o después de modi-
ficar una fila individual. Por el contrario, un trigger a nivel de operación se dispara
después de que se ejecute una operación completa que puede afectar a varias fi-
las. Recuerde que SQL permite instrucciones como la siguiente:
delete from Clientes
where Ciudad in ("Pompeya", "Herculano")
Si la base de datos en cuestión sólo ejecuta sus triggers al terminar las operaciones,
será mucho más complicada la programación de los mismos, pues más trabajo
costará restablecer los valores anteriores y posteriores de cada fila particular.
También debe tenerse en cuenta las posibilidades de extensión del lenguaje, por
ejemplo, incorporando funciones definidas en otros lenguajes, o el poder utilizar
servidores de automatización COM o CORBA, si se permiten o no llamadas re-
cursivas, etc.
• Implementación de transacciones: recuperación y aislamiento
Este es mi otro criterio de análisis preferido. Las transacciones ofrecen a las ba-
ses de datos la consistencia necesaria para que operaciones parciales no priven de
sentido semántico a los datos almacenados. Al constituir las unidades básicas de
procesamiento del servidor, el mecanismo que las soporta debe encargarse tam-
bién de aislar a los usuarios entre sí, de modo que la secuencia exacta de pasos
concurrentes que realicen no influya en el resultado final de sus acciones. Por lo
tanto, hay dos puntos en los que centrar la atención: cómo se implementa la
atomicidad (la forma en que el sistema deshace operaciones inconclusas), y el
método empleado para aislar entre sí las transacciones concurrentes.
• Segmentación
Es conveniente poder distribuir los datos de un servidor en distintos dispositivos
físicos. Al situar tablas en distintos discos, o segmentos de las propias tablas, po-
demos aprovechar la concurrencia inherente a la existencia de varios controlado-
res físicos de estos medios de almacenamiento. Esta opción permite, además,
Sistemas de bases de datos 41
superar las restricciones impuestas por el tamaño de los discos en el tamaño de la
base de datos.
• Replicación
Uno de los usos principales de la replicación consiste en aislar las aplicaciones
que realizan mantenimientos (transacciones OLTP) de las aplicaciones para toma
de decisiones (transacciones DSS). Las aplicaciones con fuerte base OLTP tien-
den a modificar en cada transacción un pequeño número de registros. Las aplica-
ciones DSS se caracterizan por leer grandes cantidades de información, siendo
poco probable que escriban en la base de datos. En sistemas de bases de datos
que implementan el aislamiento de transacciones mediante bloqueos, ambos ti-
pos de transacciones tienen una coexistencia difícil. Por lo tanto, es conveniente
disponer de réplicas de la base de datos sólo para lectura, y que sea a estos clones
a quienes se refieran las aplicaciones DSS.
Me da un poco de vergüenza añadir el último factor a la lista anterior: el precio. To-
dos queremos lo mejor, pero no siempre estamos dispuestos a pagar por eso. Así que
muchas veces una decisión de compra representa un balance entre la calidad y el
precio ... como en todo.
InterBase
Los antiguos griegos representaban a la Fama y a la Fortuna como caprichosas diosas
que otorgaban sus favores muchas veces a quienes menos lo merecían; estos griegos
de antes, la verdad, eran bastante misóginos, entre otras cosas. En cualquier caso,
InterBase debe haber tenido algún altercado con la señorita Fama, porque no tiene la
popularidad que merecería por sus muchas virtudes.
Una de estas virtudes es que se puede instalar el servidor en muchos sistemas opera-
tivos: Windows NT y 9x, NetWare, Solaris, HP-UX, SCO, Linux...Otra es que en
cualquiera de estos sistemas ocupa muy poco espacio, del orden de los 10 ó 20 MB.
El mantenimiento de un servidor, una vez instalado, es también mínimo. Cada base
de datos se sitúa en uno o más ficheros, casi siempre de extensión gdb. Estos ficheros
crecen automáticamente cuando hace falta más espacio, y no hay que preocuparse
por reservar espacio adicional para registrar los cambios efectuados por las transac-
ciones, como en otros sistemas. Se pueden realizar copias de seguridad de una base
de datos “en caliente”, mientras que otros sistemas requieren que no existan usuarios
activos para efectuar esta operación. Y la recuperación después de un fallo de hard-
ware es sencilla e inmediata: vuelva a encender el servidor.
42 La Cara Oculta de C++ Builder
Tal sencillez tiene un precio, y es que actualmente InterBase no implementa directa-
mente ciertas opciones avanzadas de administración, como la segmentación y la re-
plicación. Esta última debe ser implementada manualmente, por medio de triggers
definidos por el diseñador de la base de datos, y con la ayuda de un proceso en se-
gundo plano que vaya grabando los datos del original a la réplica. No obstante, In-
terBase permite definir directamente copias en espejo (mirrors) de una base de datos,
de forma tal que existan dos copias sincronizadas de una misma base de datos en
discos duros diferentes del mismo servidor. De este modo, si se produce un fallo de
hardware en uno de los discos o controladores, la explotación de la base de datos
puede continuar con la segunda copia.
En lo que atañe a los tipos de datos, InterBase implementa todos los tipos del están-
dar SQL con una excepción. Este lenguaje define tres tipos de campos para la fecha y
la hora: DATE, para fechas, TIME, para horas, y TIMESTAMP para almacenar
conjuntamente fechas y horas. InterBase solamente tiene DATE, pero como equiva-
lente al TIMESTAMP del estándar. Esto en sí no conlleva problemas, a no ser que
haya que escribir una aplicación que acceda indistintamente a bases de datos de In-
terBase y de cualquier otro sistema SQL. Pero cuando estudiemos el uso del Diccio-
nario de Datos de C++ Builder, veremos cómo resolver esta nimiedad.
InterBase tiene, hoy por hoy, una de las implementaciones más completas de las
restricciones de integridad referencial, pues permite especificar declarativamente la
propagación en cascada de borrados y modificaciones:
Borrados Modificaciones
Prohibir la operación Sí Sí
Propagar en cascada Sí Sí
Asignar valor por omisión Sí -
Por supuesto, tenemos todas las restricciones de unicidad, claves primarias, valida-
ciones a nivel de registro (cláusulas check). Estas últimas son más potentes que en el
resto de los sistemas, pues permiten realizar comprobaciones que involucren a regis-
tros de otras tablas.
Sistemas de bases de datos 43
Los triggers de InterBase se ejecutan antes o después de cada operación de actualiza-
ción, fila por fila, que es como Dios manda. Por otra parte, tiene un lenguaje de pro-
cedimientos almacenados muy completo, que permite llamadas recursivas, y la defini-
ción de procedimientos de selección, que devuelven más de un registro de datos por
demanda. Todo ello se integra con un mecanismo de excepciones muy elegante, que
compagina muy bien con las técnicas transaccionales. Es posible, además, extender el
conjunto de funciones del lenguaje mediante módulos dinámicos, DLLs en el caso de
las versiones para Windows y Windows NT.
Pero la característica más destacada de InterBase es la forma en la que logra imple-
mentar el acceso concurrente a sus bases de datos garantizando que, en lo posible,
cada usuario no se vea afectado por las acciones del resto. Casi todos los sistemas
existentes utilizan, de una forma u otra, bloqueos para este fin. InterBase utiliza la
denominada arquitectura multigeneracional, en la cual cada vez que una transacción mo-
difica un registro se genera una nueva versión del mismo. Teóricamente, esta técnica
permite la mayor cantidad de acciones concurrentes sobre las bases de datos. En la
práctica, la implementación de InterBase es muy eficiente y confiable. Todo esto lo
estudiaremos en el capítulo 12, que trata acerca de las transacciones.
La última versión de InterBase, en el momento en que escribo estas líneas, es la 5.5, y
acompaña a C++ Builder 4: en la versión Profesional con licencias para InterBase
Local, y en la Cliente/Servidor, con licencias para un servidor sobre Windows 9x y
NT.
Microsoft SQL Server
Toda semejanza en la explicación de las características de Microsoft SQL Server con
las de Sybase será algo más que una simple coincidencia. Realmente MS SQL Server
comenzó como un derivado del servidor de Sybase, por lo que la arquitectura de
ambos es muy parecida. De modo que gran parte de lo que se diga en esta sección
sobre un sistema, vale para el otro.
Es muy fácil tropezarse por ahí con MS SQL Server. Hay incluso quienes lo tienen
instalado y aún no se han dado cuenta. Microsoft tiene una política de distribución
bastante agresiva para este producto, pues lo incluye en el paquete BackOffice, junto
a su sistema operativo Windows NT y unos cuantos programas más. Como puede
imaginar el lector, SQL Server 6.5 puede ejecutarse en Windows NT y en Windows
NT. Por fortuna, la versión 7.0 ofrece un servidor para Windows 9x ... aunque obliga
al usuario a instalar primeramente Internet Explorer 4.
Lo primero que llama la atención es la cantidad de recursos del sistema que consume
una instalación de SQL Server. La versión 6.5 ocupa de 70 a 90MB, mientras que la
44 La Cara Oculta de C++ Builder
versión 7 llega a los 180MB de espacio en disco. ¿La explicación? Asistentes, y más
asistentes: en esto contrasta con la austeridad espartana de InterBase.
A pesar de que la instalación del servidor es relativamente sencilla, su mantenimiento
es bastante complicado, sobre todo en la versión 6.5. Cada base de datos reside en
uno o más dispositivos físicos, que el fondo no son más que vulgares ficheros. Estos
dispositivos ayudan a implementar la segmentación, pero no crecen automática-
mente, por lo que el administrador del sistema deberá estar pendiente del momento
en que los datos están a punto de producir un desbordamiento. A diferencia de In-
terBase, para cada base de datos hay que definir explícitamente un log, o registro de
transacciones, que compite en espacio con los datos verdaderos, aunque este registro
puede residir en otro dispositivo (lo cual se recomienda).
Aunque los mecanismos de logging, en combinación con los bloqueos, son los más
frecuentes en las bases de datos relacionales como forma de implementar transaccio-
nes atómicas, presentan claras desventajas en comparación con la arquitectura multi-
generacional. En primer lugar, no se pueden realizar copias de seguridad con usua-
rios conectados a una base de datos. Los procesos que escriben bloquean a los pro-
cesos que se limitan a leer información, y viceversa. Si se desconecta físicamente el
servidor, es muy probable que haya que examinar el registro de transacciones antes
de volver a echar a andar las bases de datos. Por último, hay que estar pendientes del
crecimiento de estos ficheros. Hay un experimento muy sencillo que realizo con
frecuencia en InterBase, poblar una tabla con medio millón de registros, que nunca
he logrado repetir en SQL Server, por mucho que he modificado parámetros de
configuración.
Hay que reconocer que esta situación mejora un poco con la versión 7, pues desapa-
rece el concepto de dispositivo, siendo sustituido por el de fichero del propio sistema
operativo: las bases de datos se sitúan en ficheros de extensión mdf y ndf, los registros
de transacciones, en ficheros ldf. Este nuevo formato permite que los ficheros de
datos y de transacciones crezcan dinámicamente, por demanda.
Otro grave problema de versiones anteriores que soluciona la nueva versión es la
granularidad de los bloqueos. Antes, cada modificación de un registro imponía un
bloqueo a toda la página en que éste se encontraba.

Outros materiais