UNIVERSIDAD AUTONOMA METROPOLITANA

Anuncio
UNIVERSIDAD
AUTONOMA
METROPOLITANA
UNIDAD:
IZTAPALAPA
DIVISION:
CIENCIAS BASICAS E INGENIERIA
CARRERA:
INGENIERIA ELECTRONICA
MATERIA:
PROYECTO DE INGENIERIA ELECTRONICAI Y II
TITULO:
INTERFACES DE PROGRAMACION DE
APLICACIONES PARA CONEXION A
BASES DE DATOS.
ODBC, UNA API DE VISUAL BASIC Y JDBC.
FECHA:
MARZO DE 1999
ALUMNO:
GARCIA CUEVAS JUVENAL
MATRICULA:
89327433
ASESOR:
LUIS FERNANDO CASTRO CAREAGA
Interfaces de Programaciónde Aplicaciones
para conexión a bases de datos
Interfaces de Programación de
Aalicaciones
aara
conexión a bases de datos
ODBC, una API de Visual Basic y JDBC
Juvenal Garcia Cuevas
División de Ciencias Básicas e Ingeniería
Universidad Autónoma Metropolitana
Unidad lztapalapa
1
Revisión
Ing. Luis Fernando Castro Care
Departamento de Computación
Universidad Autónoma Metro
Unidad lztapalapa
Interfaces de Programación de Aplicaciones para conexión
a bases de datos
ODBC, una API de Visual Basicy JDBC
Juvenal Garcia Cuevas
El contenido de ésta obra corresponde a la
documentación del proyecto de Ingeniería ElectrónicaI y II
llevado a término por el autor, de acuerdo
con el plan de estudios vigentede la
Universidad Autónoma Metropolitana
Impreso en México
Esta obra se terminó de
imprimir en Marro de1999
en las instalacionesdel Edificio T de
Ciencias Básicas e Ingeniería de
la
Universidad Autónoma Metropolitana
Unidad Iztapalapa,
Av. Michoadn y la Purísima
Col. Vicentina
Delegación lztapalapa
09340 México, D.F.
Se imprimieron3 ejemplares
Para todas aquellas personas que de un modo u otro contribuyeron en la creación de éste trabajo
...
... ya sea en forma metafísica, mística, espiritual, activao cognoscitiva.
Prólogo
Se ha dicho que la necesidad es madre de
la inventiva, y se hadichobien.Antesdequeyo
siquiera pensaraen terminar mis estudiosen la UAM Iztapalapa,el profesor Luis Castrome invitó a
participar en un proyecto avalado por la universidad. Este consistía en el desarrollo de sistemas
para el corporativo PEMEX REFINACION, con sede en el puerto de Veracruz. Para mí era una
excelente oportunidad de andar nuevamente en
el camino de la Ingeniería de Software y de probar
las habilidades adquiridas durante el ciclo universitario, pues antes de ello trabaje exclusivamente
en el campo de las redes computacionales.
Durante las primeras cinco semanas de desarrollo para
el convenio PEMEX-UAM, huboel requisito
de acceso a bases de datos por ODBC. En la primera semana me dediqué a investigar sobre el
tema,desdesaberquesignificabaODBChasta
la manerade utilizarlo. ODBCcuentacon un
conjuntoespecíficodefuncionespararealizarlastareasdeconexiónydeejecuci6nde
instruccionesdeSQL,peroesono
estodo,algunasdelasfuncionesrequieren
de unagran
cantidad de argumentos, cada uno con un objetivo especial, inclusive se utilizan apuntadores.
Esto no habría significadogran cosa de haberse usadoel lenguaje C, pero el problema radicaba en
quelaherramientaescogidapara
el desarrolloeraVisualBasic
y sehabíandescartado
los
mecanismosdeaccesoadatosporRDO
y DA0 por excederse en los tiempos de respuesta.
Finalmente me dedique a experimentar el uso de las funciones de ODBC dentro de Visual Basic.
Elaboré infinidad de pequehas pruebas para cada una de las funciones que a mi juicio serían las
más útiles a nuestras necesidades. Poco a poco, las pruebas que había elaborado me revelaron
patrones acentuados en cuanto a la forma de disponer de las funciones de ODBC y convine en
aprovechar tal comportamiento parael beneficio general, creandouna lnterfaz de Programación de
Visual Basic basada enODBC. Los resultados obtenidos fueron satisfactorios.
Posterior al desarrollo en Visual Basic, surgió un nuevo desarrollo para Web, al igual con miras a
consultarunabasededatos,
de aquí mi conocimientosobreJDBC,puesen6saocasiónla
plataforma fue Java.
En esta obra, que presento como proyecto terminal, expongo
las experiencias y conocimientos
adquiridos en el campo de la conexión a bases de datos. Los temas se dividen en tres grupos a
saber:ODBC, la lnterfaz de conexiónabases de datosparaVisual Basic-que hellamadola
biblioteca de funciones- y finalmente, JDBC.
Contenido
Prólogo
¡x
Introducción
xv
PARTE I. ODBC
i
I Aspectos generales de ODBC
3
1.1 La Conectividad a Bases de Datos Abiertas
Porqué usar ODBC
1.2 Los Drivers y el Driver Managerde ODBC
El Driver Manager de ODBC
ODBC Desktop Database Drivers
1.3 Registro de una fuente de datos
Registrando una fuente de datos en el código
2 La API de ODBC
9
2.1 El enfoque Cliente/Servidor
2.2 Objetos de Datos Remotos o llamadas a funciones de la API de ODBC
2.3 Codificación directa a la API deODBC
9
11
12
13
14
Arquitectura del modelo de codificación directa
2.4 La librería deenlace dinámico: ODBC32.DLL
3 Conexión ODBC a basesde datos
3.1 Primero: Se requiere un handle de ambiente
La función SQLAllocEnv ( )
3.2 Segundo: Se requiere un handle de conexión
La función SQLAllocConnect ( )
3.3 Tercero: Se procede a la conexión
Requisitos para la conexión
Creando el nombre de fuente de datos (DSN) de ODBC
Tres maneras de culminar la conexión
La función SQLConnect ( )
3.4 Ultimo: Se liberan los recursos usados
La función SQLDisconnect ( )
La función SQLFreeConnect ( )
La función SQLFreeEnv ( )
3.5 Formato básico de unaaplicación ODBC
xi
IS
15
15
16
17
17
18
18
18
19
21
21
22
23
23
3.6 Conexiones múltiples y manejo de errores
Manejo de errores
La función SQLError ( )
Recuperando mensajesde error
Mensajes de error de ODBC
Formato del mensaje de error
3.7 Los códigos de retornoy los tipos de datos
Los tipos de datos
4 El manejo de instrucciones de SQL
4.1 Lo primordial: El handle desentencia
La función SQLAllocStmt ( )
4.2 SQLExecDirect: Ejecutar instrucciones de SQL
La función SQLExecDirect ( )
4.3 SQLBindCol: Asociando variables y columnas
El manejo de variables de Visual Basic y SQLBindCol
Usando cadenas deVisual Basic con SQLBindCol
Usando memoria global: funciones dela WinAPI
La función SQLBindCol ( )
4.4 SQLFetch: Navegar por los resultados
La función SQLFetch ( )
4.5 SQLGetData: Recuperando la informaciónpor columnas
La función SQLGetData ( )
4.6 Esquema general de procesamientode instrucciones de SQL
5 Resumen de funciones deODBC
5.1 Niveles de conformidad
5.2 Funciones y niveles de conformidad
Funciones del núcleo
Funciones del Nivel 1
Funciones del Nivel 2
Para más información
25
26
27
29
29
30
31
31
33
33
34
35
35
37
37
38
39
41
44
44
46
47
49
51
51
52
52
54
55
56
PARTE II. La biblioteca de funciones
57
6 Sobre la biblioteca de funciones
59
6.1 Objetivo y alcance de lasfunciones
6.2 Tipos de Datos Abstractos utilizados
El tipo Base de Datos
El tipo Registro de SQL
El tipo Consulta de SQL
Definiciones deconstantes para códigosde retorno
6.3 Llamadas a laAPI de ODBC involucradas
59
60
60
60
61
61
62
7 Conexion.bas: La biblioteca de funciones
7.1 La función ConectarBD
7.2 La función ConectarBD2
7.3 La función HacerConsultaSQL
7.4 La función HacerEscDirectaSQL
La función HacerEscrituraSQL
7.5 La función EjecutarSQL
7.6 Las funciones de navegación de resultados
7.7 La función CerrarInstrucSQL
7.8 La función DesconectarBD
7.9 La función ErroresNativos
7.10 Las funciones privadas
La función privada DescErrorODBC
La función privada RepUltimaConsulta
65
65
66
68
69
70
70
71
72
73
74
74
75
75
77
8 Uso de las funciones
77
80
81
8.1 Un ejemplo sencillo
8.2 Esquema deuso de las funciones
8,3 Nuevamente el manejo de errores
PARTE 111. JDBC
83
9 Introducción a JDBC
85
9.1 Que es JDBC
Qué es lo que hace JDBC
JDBC es una API de bajo nivel y es la base de APIs dealto nivel
9.2 JDBC versus ODBC y otras APIs
9.3 La arquitectura de JDBC
Acceso de la API JDBC a las bases dedatos
10 Conexión JDBC a bases de datos
85
86
86
87
88
89
91
91
92
93
94
94
95
96
98
10.1 Las clases del paquete java.sq1
Interfaces de JDBC
Objetos de JDBC
Excepciones de JDBC
10.2 Conexión con la base de datos
La interfaz Driver
El objeto DriverManager
Sobre los URLs de JDBC
xiii
10.3 Creación y ejecución de sentencias de SQL
La interfaz Connection
La interfaz Statement
El objeto Resultset
Un ejemplo simple de ejecucibnde instrucciones de SQL
10.4 Las herramientas de JDK
javac-El compilador deJava
java-El Intkrprete de Java
Compilando y corriendo un ejemplo
Para más infomacibn
99
1O0
1O0
1o1
102
103
104
105
106
1o9
PARTE IV. Apéndices
111
A Declaración de las funciones de la API de ODBC.
113
B Conexion.bas: Código de las funciones.
133
Bibliografía
157
lndice
159
xiv
Introducción
La conexión a bases de datos abiertas es uno de los temas más importantes en la industria de la
computación. La necesidad de comunicación con los distintos sistemas de bases de datos para el
acopio de información ha dado paso a uno delos estándares más revolucionarios en el terreno de
la informática: La Open Database Connectivity u ODBC, la cual es ahora una de las herramientas
más utilizadas en el desarrollo de aplicaciones que necesitanel acceso a múltiples bases de datos
con un alto grado de
eficiencia y confiabilidad. Más recientemente, ha visto la luz
el similar de
ODBCpara el desarrollodeaplicacionesparaaccesoabasesdedatosen
el Web: LaJava
Database Connectivity o JDBC, que ofrece un cúmulo de posibilidades y que muchas firmas de
software han comenzado a explotar.
Este trabajo trata de la conexión a las bases de datos utilizando la API de ODBC y las clases de
JDBC.SepresentatambiknunaAPIdeVisualBasicbasadaenODBC.LaAPI(Application
Programming Interface, lnterfaz deprogramacidndeaplicaciones)deODBC,es
el conjuntode
funcionesde la Librería deEnlace D i n h i c o ODBC32.DLLparalaconexiónabasesdedatos
abiertas (Open Database Connectivity, Conectividad a bases de datos abiertas) mediante
la cual
es posible acceder a cualquier base de datossin importar cual sea. La conexión a bases de datos
desde Java se logra con JDBC (Java Database Connectivity, Conectividad a bases de datos de
Java), la cual es tambien proporcionada por las clases recientemente incorporadas
al JDK en su
versi6n 1.Ipor Sun Microsystems.
La información contenida aquí sedivide en tres partes. En la primera se realiza un breve estudio de
ODBC y como es que permite hacer conexiones a bases de datos múltiples, se hace tambi6n una
descripcidn de la API y de las llamadas a 6sta para usar sus recursos. En
la segunda parte se
estudian las funciones basadas en ODBC construidas en Visual Basic y la forma de explotarlas.
Finalmente, en la tercera parte, se revisa la forma de usar la interfaz de JDBC para la conexión a
o desde la Internet.
bases de datos desde Java dentro de una intranet.
xv
PARTE I. ODBC
O Aspectos generales de ODBC
O La API de ODBC
O Conexión ODBC a bases de datos
O El manejo de instrucciones de SQL
O Resumen de funciones de ODBC
1
Aspectos generales de ODBC
Para hacer uso de la conectividad a bases de datos abiertas, es necesario contar con los drivers
adecuados de ODBC de las bases de datos que se deseen accesar,
as¡ como del administrador de
fuentesdedatosdeODBCparadisponer
de lasbases de datos. En &te capítuloseda una
introducción sobre ODBC y se describen los controladores o Drivers que componen la interfaz de
ODBC y el uso del administrador de fuentesde datos ODBC.
1.1 La Conectividad a Bases de Datos Abiertas
ODBC son las siglas para Open Database Connectivity (conexión a bases
de datos abiertas), la
cual es una especificación de Microsoft. ODBC fue creado por el SQL Access Group y su primera
liberaciónfueenSeptiembrede1992.
AI mismotiempoMicrosoftWindowsfue
el primero en
UNIX, OS/2,y
proporcionarunproductoODBC,ahora
ya existenversionesparaplataformas
Macintosh.
ODBC
es
unestandar
o una lnterfaz de Programacidn de Aplicaciones(API,Application
ProgrammingInterface)para
el accesoalasbasesdedatos.EstaAPIesindependiente
de
cualquiersistemamanejadordebases
de datos o sistemaoperativo;laAPIdeODBCes
independiente del lenguajede programación. LaAPI de ODBC esta basada en las especificaciones
CLIdeX/OpeneISO/IEC.ODBC
3.0 implementa
ambasespecificaciones-lasversiones
anteriores de ODBC se basaron en las versiones preliminares de 6stas especificaciones pero no
las
implementaron-y
adicionaron
características
requeridas
por los desarrolladores
de
aplicaciones de bases de datos basadasen pantallas, tales comolos cursores navegables.
AI usar llamadas a funciones ODBC en un programa se pueden acceder a archivos de varias y
diferentesbases de datos,incluyendoAccess,dBase,Excel
y Texto. AdemAs del softwarede
3
4
ODBC, es necesario un controlador o driver para cada base de datos que es accesada. Microsoft
es quien principalmente proponey proporciona el soporte a la programaci6n con ODBC.
ODBC está basado y estrechamente alineado al Open Group Standard Structured Query Language
(SQL) Call-Level Interface (CLI). Esto permite a los programas usar consultas SQL que accesarán
alasbasesdedatos
sin tenerquepreocuparsede
las interfacespropietariasdelasmismas.
ODBC maneja las consultas SQL y las convierte en consultas interpretables por cada sistema de
base de datos individual.
Porqué usar ODBC
ODBC proporciona una manera uniforme de definir fuentes de datosy sus respectivos metodos de
acceso a las mismas. ODBC está disefiado basándose en SQL y las bases de datos relacionales.
La especificación de ODBC define llamadas de nivel bajo a la API que cualquier aplicaci6n puede
usar para consultar una base de datos. AI escribir llamadas a
la API una aplicaci6n cualquiera
puede accesar fuentes de datos heterogeneas con
s610 un código fuente.
ODBC permite a las aplicaciones el acceso a los datos en una forma común, la cual les da a las
aplicaciones
portabilidad,
agiliza
su
desarrollo
y facilita
la
curva
de
aprendizaje
de
los
desarrolladores cuando se requieren múltiples fuentes de datos. ODBC está reconocido como un
estándar en el acceso de datos.
1.2 Los Drivers y el Driver Manager de ODBC
ODBC estádiseñadoparaunmáximainteroperabilidad,estoes,lahabilidaddeunaaplicaci6n
para accesar diferentes sistemas manejadores de bases de datos (DBMS) con
el mismo cbdigo
fuente. Las aplicaciones de bases de datos llaman a las funciones en la interfaz de ODBC, la cual
está implantada en m6dulos propietarios de la base de datos específica llamados controladores (en
ingles Drivers). El uso de controladores aísla a las aplicaciones de las llamadas específicas de una
basededatosenlamismaformaenque
los controladoresdelasimpresoras
aislan a los
programasprocesadoresdetextosde
los comandosespecíficosdelasimpresoras.Como
los
controladores son cargados en tiempo de ejecucidn, un usuario s610 tiene que agregar un nuevo
controlador para accesar a un nuevo DBMS; no es necesario recompilar
o reenlazar la aplicaci6n.
Las funciones en la API de ODBC son implementadas porlos desarrolladores de los controladores
deDBMSespecíficos.Lasaplicacionesllamanalasfuncionesenesoscontroladorespara
el
acceso a datos en una forma independiente al DBMS. Un administrador de controladores maneja
la comunicaci6n entrelas aplicaciones y los controladores.
AunqueMicrosoftproporcionaunadministradordecontroladores
(Driver Manager)paralas
computadoras que corren Windows NT Server, Windows NT Workstation, y Windows 95; se han
escrito varios controladores de ODBC, así comolas llamadas a las funciones de ODBC de algunas
de sus aplicaciones; cualquiera puede escribir aplicaciones y controladores de ODBC. De hecho,
la
mayoría de las aplicaciones y controladores de ODBC disponibles para computadoras que corren
los sistemas antes mencionados son producidos por otras compafiías además de Microsoft,
los
controladores y las aplicaciones de ODBC existen tambien para Macintoshy una gran variedad de
plataformas UNIX.
5
Paraayudara los desarrolladores de controladores y aplicaciones, Microsoft ofrece el Kit para
Desarrollo de Software ODBC (SDK ODBC) para computadoras con Windows
NT Server, Windows
NT Workstation, y Windows95, el cual proporciona el DriverManager, el instaladordeDLL,
herramientas para pruebas, y aplicaciones de ejemplo.
Es importante entender que ODBC este disefiado para explotar las capacidades de las bases de
datos, no para sustituirlas. Por esto, los escritores de aplicaciones no deben esperar que usando
ODBC repentinamente transformart!tn una simple base de datos en un sistema completo de base
de datos relacional. Tampoco hay escritores de controladores que implementen funcionalidades
que no hay en las bases
de datos conocidas. Una excepcibn a esto
es que los desarrolladores
quienes escriben controladores que directamente accesan archivos de datos
(tales como los datos
en un archivo Xbase) requieren escribir un sistemade base de datos que soportela funcionalidad
mínima de SQL. Otra excepcibn es el ODBC SDK, el cual proporciona una librería que simula los
cursoresnavegablesparacontroladoresqueimplementenuncierto
nivel de funcionalidad. Las
aplicaciones que usan ODBC son responsables de cualquier funcionalidad que implique basesde
datoscruzadas. Porejemplo,ODBCnoesunsistema
de unionesheterogéneas,niesun
procesador de transacciones distribuidas. Sin embargo, como es independiente del DBMS, puede
ser usado para construir tales herramientas de bases de datos cruzadas.
El Driver Manager de ODBC
El administrador de controladores de ODBC u ODBC Driver Manager, proporciona la interfaz entre
el host y el back-end del controlador de la fuente de datos. El administrador de controladores es
responsable de:
Cargar el controlador de la base de datos remota especificado por la entrada de nombre de
fuente de datos.
lnicializarlainterfaz.
Proporcionar puntos de entrada a los correspondientes del controlador.
Validar paremetros y manejar la serializacibn de funciones de ODBC.
El administrador de controladores de ODBCesuna Librería de Enlace Dinemico (dynamic link
library, DLL)-en particular se trata del archivoODBC32.DLL-que puede hacer de interfaz con un
back-end (servidor) de un sistema de base de datos o un tipo específico de archivo implementado
como una basede datos.
Hay otros controladores especiales para cada tipo de base de datos, que conectan al Microsoft
SQL Server, a bases de datos Sybase SQLServer, Oracleo Microsoft Visual FoxPro. Siempreque
esposible, el controladortomaventajadelascaracterísticasback-endespecíficas,como
los
cursores o lasconsultasparametrizadas.
En algunoscasos, el controladoren sí cuentacon
funciones específicas para suplir las características no soportadas por el back-end de la base de
datos. Si el controlador no soporta la caracteristica requerida, éste regresa un error indicando que
es incapaz de realizarla operacibn.
ODBC Desktop Database Drivers
Los ODBC Desktop Database Drivers de Microsoft permiten abrir y consultar las bases de datos a
través de la interfaz de ODBC. Estos controladores trabajan con ODBC 2.5, pero se incluyen con
ODBC 3.0. Los controladores estan disenados para su uso con Microsoft Windows 95
(o posterior),
6
o Windows NT 3.51 (o posterior). S610 se soportan aplicaciones de 32
Windows NT se soportan aplicaciones de16 bits y de 32 bits.
bits en Windows 95; en
Los ODBC Desktop Database Drivers incluyen controladores
de 32 bits para Microsoft Access,
dBase, Microsoft Excel, Microsoft FoxPro, Paradox y Texto (Un controlador para Microsoft FoxPro
3.0 esta disponible por separado). No se tienen controladores de 16 bits. La Figura 1 muestra una
lista de los controladores que estan disponibles para Windows. Cualquier otro controlador para
cualquier otra base de datos que se desee agregar es necesario adquirirlo por separado con
la
compañía que fabric6la base de datos.
3.50.360... Microsoft Corp...
f)
3.50.360...Microsoft Corp...
MicrosoftODBCDriver for Oracle2.00.006 ... Microsoft Corp...
b ) 3.50.%O... Microsoft Corp...
csv) 3.50.360... Microsoft Corp...
odbcit32.dll
odbcjt32.dll
MSORCL1O.DLL
odbcit32.d
odbcit32.dll
2.00.0301 Oracle Corpor... sqo32-73.d
2.65.0240 Microsoft Corp... sqlsrv32.dll
Figura l.ODBC Desktop Database Drivers.
1.3 Registro de una fuente de datos
El primer paso en el acceso a datos por ODBC es utilizar el manejador de fuentes de datos de
ODBC pararegistrar la fuentededatos.Estepasoesimportante
ya queasísealmacenala
inforrnacidn de la fuente de datos en el Registro de Windows y hace esta informaci6n disponible
para las aplicaciones.
Para dar de alta una fuente de datos:
1) En el Panel de Control de Windows, dar doble-click enel icono 32bit ODBC.
2)Darclicken
Agregar... paradesplegar el dialogo Crearnuevafuentededatos,
luego se
selecciona el controlador ODBC para la fuentede datos que se desee accesar. Por ejemplo se
puede seleccionar Microsoft SQL Server.
7
En el cuadro de Configuraci6n, teclear el nombre de la fuente de datos o Data Source Name
(DSN). Este puede ser cualquier cadena, como "VentasDB" o "Pubs". La cadena no tiene que
corresponder con el nombre actualde la base de datoso tabla quese desea accesar.
Opcionalmente, teclear una descripción de la base de datos, como "Datos deVentaspara
1998.Se puede teclear cualquier texto.
Teclear el nombre de red del servidor en el cual reside la fuente de datos. No alladir el doblebackslash ("\\") para comenzar el nombre.
Teclear el nombre de la base de datos que se accesara.Por ejemplo, para especificar la base
de datosde ejemplo deMicrosoft SQL Server, teclear "Pubs".
La configuración para cada fuente de datos ODBC puede variar debido a que cada controlador
requiere de un conjunto diferente de información. Si el dialogo de configuración de la fuente de
datos que se esta agregando tiene valores no descritos en los pasos mostrados arriba, haga click
en el botón de ayuda de la caja de dialogo para mas información.
Registrando una fuente de datos en el código
En algunos casos es deseable registrar la fuente de datos dentro
del c6digo en lugar de dejarles a
los usuarios el trabajo de configurarla con el manejador de fuentes de datos. Para hacer esto, se
utiliza el m6todo RegisterDatabasedel objeto DBEngine en Visual Basic5.0.
El procedimiento mostrado enel Listado 1 registra una fuentede datos llamada "Cuentas" para una
base de datos del mismo nombreen el servidor "ServCuentas".
Listado 1. Registro de una fuentede datos en Visual Basic.
Sub RegisterDB
()
Dim str As String
' Construye la cadenade información.
str = "Description=SQL Server en Servidor ServCuentas" &
vbCr & "OemToAnsi=No" &
vbCr & "Network=(Default)"
& vbCr & "Address=(Default)" & vbCr & "Server=ServCuentas" & vbCr & "Database=Cuentas"
-
' Registra la base de datos
DBEngine .RegisterDatabase "Cuentas",
"SQL Server", True, str
End Sub
Cabemencionarquedependiendo
de la basededatos, los valoresque se incorporaranala
cadena de información seran diferentesen cada caso. El listado anterior es parael caso específico
del manejador de bases de datos de Microsoft
SQL Server.
2
La API de ODBC
La lnterfaz de Programación de Aplicaciones (API) de la Conectividad de Bases de Datos Abiertas
(ODBC) define un modelo de programación independiente de la base de datos que proporciona
una sola interfaz que se puede usar para accesar cualquier base de datos o servidor de base de
datosquetengauncontroladorODBC.AIusarla
API deODBC,sepuedendesarrollar
aplicaciones que tengan el rendimiento y flexibilidad de los modelos de programación de código
nativo. AI mismo tiempo, es posible mantener una aproximación general de programación universal
que puede ser aplicado a diversos formatos
de bases de datos.
Este capítulo da una breve descripción de la API de
ODBC para tomar una decisión adecuada
sobre el modelo de programación a utilizar en un aplicación ClientelServidor.
2.1 El enfoque ClientelServidor
La API de ODBC es una interfaz de nivel de llamada (Call-Level Interface, CLI) alos controladores
y libreríasdeODBC.Estaslibreríasproporcionanconectividadparaaccesoadatoshacia
el
Microsoft SQL Server y hacia cualquier otra basede datos que proporcioneun controlador ODBC.
AI codificar con esta interfaz, se puede crear código independiente de
la base de datos, lo cual
significa
que
la
API
de ODBC
proporciona
un
modelo
de
programación
universal
que
automaticamente se adapta a una gran variedad de bases de datos.
La API de ODBC a menudo es extendida con funciones especialesdel controlador en sí-ademas
de las que pertenecen al manejador del controlador ODBC. Por ejemplo, el controlador del SQL
Server contiene varias funcionesde su API las cuales no estan documentadas fuera
del ambit0 del
controlador. Ademas, esas funciones realizan tareas específicasdel controlador, su uso podría no
ser soportado en otros controladores. Si una aplicación esta pensada para ser utilizada dentro de
9
10
una amplia variedad de sistemas back-end, se deben usar esas funciones
con sumo cuidado o no
utilizar todas las que hay.
LaAPIdeODBCproporcionaunextensocontrolsobre
los errores y los mensajesypermite
manejarla mayoria de las características de los servidores de back-end. La API de
ODBCno
implementa el ligadodecontrolescondatos,pero
sí cuentaconsuspropiosconjuntos
de
resultados que utilizan cursores tipo client-side
o tipo server-side.
El modelo de programacidnde la API de ODBC proporciona las siguientes características:
Un modelo de programaci6n universal que puede accesar ala mayoría de las arquitecturas
de bases de datos.
Una interfaz nativa con Microsoft SQL Server.
Un manejo inteligente de parametros de
Stored Procedures.
6.0.
Soporte a cursores server-side
en Microsoft SQL Server versidn
Implernentacion de cursores keyset, dynamic, static
y forward-only.
Manejo avanzadode conjuntos de resultados.
Acceso a virtualmente todas las características de
SQL Server.
Manejo completode errores post-llamada.
La Figura 2 ilustra como es queVisualBasicejecutac6digo
de la APIdeODBC,
el cual
directamentemanipula los puntosdeacceso de la libreríadelmanejadordecontroladores
de
ODBC. Estos puntos de accesoseconectan al controladorquepermite el accesoa un tipo
específicodebase
de datosremotaeimplementalasoperaciones
de accesoa los datos.
Usualmente no es necesario reescribir la aplicaci6n para acceder a un tipo diferente de base de
datos. Todo lo que se necesita es cambiar
el controlador de la base de datos remota.
I
Código Visual Basic
ODBC Driver Manager
Driver
Server
Driver
U
Oracle
Remote Database Engine
t
Figura 2. Acceso a basesde datos remotas usando la API de ODBC.
11
2.2 Objetos de Datos Remotos o llamadas a
funciones de la API de ODBC
La API de ODBC ha proporcionado una interfaz confiable a
los desarrolladores de front-end de
y relativamente estable con lacual conectarse
bases de datos que necesitan una plataforma rdpida
a los sistemasClientelServidor.LaAPIde
ODBC estádisefiadaparacorrerendiversas
plataformas, incluyendo Windows de16 bits, Windows 95 y Windows NT de 32 bits, y varios otros.
Sinembargo, como lacomplejidad y laflexibilidad de dstasplataformasaevolucionado,la
complejidad para usar el modelo de programaci6n de laAPI de ODBC en Visual Basic tambien se
ha incrementado. Aunque es posible crear aplicaciones usando la API
de ODBC desde Visual
Basic, dsta no proporciona tantos beneficios comoel uso de la interfaz Remote Data Object u otras
interfaces de modelo-objeto-especialmente en
plataformas
de
32 bits.
La
conversión
de
aplicaciones ODBC API de 16
bits a 32 bits puede ser especialmente problemdtica cuando se
tienen nuevos manejos de memoria y características Unicode,y otros requerimientos de c6digo de
mayor complejidad.
En general, existen dos aproximacionesal uso de la API de ODBC:
Extensidn de RDO con la API de ODBC. Debido a que los Objetos de Datos Remotos (RDO)
son, en su mayor parte, interfaces de objetos a la API
de ODBC, tiene sentido utilizar las
funciones de la API de ODBC en conjuncibn con una aplicacidn RDO u ODBCDirect. Usar
los handles de ODBC proporcionados por las interfaces
de nivel-objeto para llamar a las
funciones de la API de ODBCpuedeserunaefectivaeinteligenteformadecontrolar
o rdoResultset.
aspectos de los objetos rdoEnvironment, rdoConnection, rdoQuery
Nota: Si se hace mal uso de ciertas funciones de la API de ODBC con handles dados por
o perdida de datos.
RDO, se corre el riesgo de fallas de protecci6n general inesperadas
Codificaci6nDirecta a la API deODBC. Es posible crear una aplicacidn usando la API
de
ODBC que nodependa de RDOuotrainterfaztipoobjetoparaobtenerhandles,abrir
conexiones, crear y manejar cursores, o realizar operaciones complejas de recuperacidn de
datos, enlazado y de actualizaci6n. Todas dstas funciones pueden ser realizadas por laAPI
de ODBC. Aunque se gana algún grado adicional de rapidez, flexibilidad y memoria con
el
uso directo de la API de ODBC, se tiene un impacto negativo en el tamano del programa y
en su rendimiento, adem& de quees mucho rndsdifícil de codificar y de mantener.
Nota: Algunos desarrolladores escogen la API de ODBC para accesar a las bases
de datos de
Microsoft Jet. Aunque es posible usar los controladores de
ODBC proporcionados con algunas
aplicaciones de Microsoft Office, dsta aproximaci6n requiere de la Jet database engine y siempre
resulta en un pobre rendimientoal compararse conel uso de los Objetos de Acceso a Datos (DAO)
para accesar este tipode base de datos. Aun más, muchas de las características mas significativas
de la Jet database no son aprovechadas por los limitados controladores Jet ODBC, de forma que
se podríanexperimentaralgunasdificultades al realizarlamayoríadelasoperacionesbdsicas
mediante dsta aproximaci6n.
Cadaunode los dos modelos arriba mencionados tiene sus ventajas
y desventajas. Sedeben
considerar todos los aspectos antes de tomar
una decisi6n sobre el modelo de programación a
utilizar. Sin embargo, el modelo que nos ocupa es el de la codificacidn directa a la API de ODBC,
que implica las llamadas a las funciones de la librería de enlazado dinAmico ODBC32.DLL.
12
2.3 Codificación directa ala API de ODBC
Se puede codificar directamente a la API de ODBC. Este modelo de programacidn utilizael mismo
administrador de controladores y controlador de ODBC específico que Jet usa. Sin embargo, es
responsabilidad del programador manejar todos los aspectos de la conexidn, consultas, búffers,
cursores y cualquier error quesea generado, dentro del cddigo
de Visual Basic.
La Figura 3 ilustra cdmo la declaracidn de sentencias de la API permite la comunicacidn con el
administrador de controladores de ODBC para acceder a datos en una base
de datos remota.
Visual Basic
+
*
*
MI Declare Statments
ODBC Driver
I
ODBC Driver
1
+
Network Interface
I
I
+
Remote Database Engine
I
Figura 3. El modelo de programación de la API de ODBC en Visual Basic.
El modelo de programacidn de la API de ODBC utiliza instrucciones Declare
de Visual Basic, el
administrador de controladores de ODBC y un controlador específico para la base de datos o
servidor. La parte de declaraci6n de funciones de la API ODBC incorpora funciones de la interfaz
de ODBC a Visual Basic y a los procedimientos que necesitan accesar la API. De esta forma las
aplicaciones de Visual Basic pueden usar las funciones de la API como cualquier otra funcidn. La
manera de hacer esto es la siguiente:
Declare Function Beep Lib "kerne132" Alias "Beep" (ByVal dwFreq As -Long,
ByVal dwDuration As Long) As Long
Declare Function BringWindowToTop Lib "user32" Alias "BringWindowToTop"
(ByVal hwnd As Long) As Long
Ambas declaraciones son para funciones de la API Win32 de Windows. En la primera se hace
referencia a la funcidn Beep ubicada en la DLL kerne132, la cual provoca que el sistema emita el
familiar sonido de acuerdo a los pardmetros de frecuencia y duracidn que le son proporcionados
como argumentos. Y la segunda: BringWindowToTop, ubicada enlaDLLuser32,esparahacer
que la ventana, cuyo handle se pasa como argumento, aparezca en primer plano.
13
Arquitectura del modelo de codificación directa
La arquitecturade Aplicación/Controlador en Windows 95 o posterior es:
Aplicación (32-bit)
I
ODBC Driver Manager
(ODBC32.dll)
I
ODBC Desktop Database Driver
(ODBCJT32.dl1, MSJET35.dI1, 32-bit Driver ISAM)
I
base de datos
El uso de &tos controladores para aplicaciones de 16 bits en Windows 95 no esta permitido. La
arquitectura de AplicaciÓnlControlador en Windows NT 3.51
o posterior es:
Aplicación (16-bit)
Aplicación
(32-bit)
I
I
I
I
I
I
ODBC Driver Manager
(0DBC.dll)
16-Bit ODBC Generic Thunking DLL
(ODBC16GT.dll)
32-Bit ODBC Generic Thunking
DLL
(ODBC32GT.dll)
I
I
ODBC Driver Manager
(ODBC32.dll)
I
I
ODBC Desktop Database Driver
(ODBCJT32.dl1, MSJET35.dl1, 32-bit Driver ISAM)
I
base de datos
Nóteseque en el casodeWindows
NT senecesitandedoslibreríasadicionalesparalas
aplicaciones de 16 bits. Estas librerías funcionan como enlace entre los Drivers de 32 bits de las
bases de datosy la vieja versión delODBC Driver Manager de 16 bits.
14
2.4 La librería de enlace dinámico: ODBC32.DLL
Una librería de enlace dinamico (en inglks, dynamic link library, DLL) es un conjunto de programas
o funciones previamente compiladas que son enlazadas en tiempo de ejecucibn por algún otro
programa que las necesite para ejecutarse. Estas librerías cuentan con una
tabla de exportacidn, la
cual indica las funciones que estan disponibles para uso público. Ademas, pueden contaro no con
una tabla deimportacibn,con la quehacenreferenciaaotras
librerías quenecesitanparasu
propiaejecucibn.LaAPIdeODBCestasustentadaprimordialmenteporlalibreríadeenlace
dinámico ODBC32.DLL, pues es en 6ste archivo donde residen-o se importan de otros drivers-la
totalidad de las funciones de ODBC que vamos a necesitar para la conexidn y la manipulacibn de
datos. Si bien se requieren de los ODBC Desktop Drivers o del Driver de la base de datos dada
para realizar la conexibn, no es conveniente hacer llamadas a las funciones de &tos Drivers, ya
que algunos incorporan sus propias funciones de ODBC y otras especiales.
Si se planea hacer uso
de las funciones de &tos Drivers conviene hacerlo con sumo cuidado por razones de portabilidad
como se vio en la primera parte de 6ste capítulo.
Vamos a hacer un brevísimo analisis dela librería de ODBC, para ello nos valdremos del programa
Quikview deWindows.Primero,busquemos
el archivoODBC32.DLL,ubicadoen
el directorio
C:\Windows\Systern\ paraWindows 95 o en C:\Winnt\System32\ paraWindows NT. Unavez
localizado el archivo hagamode un click con el botón derecho del Mouse y seleccionemos Vista
@ida o Quikview según sea el caso. Veremos desplegarse una ventana con informacidn sobre el
archivo seleccionado; pongamos particular atencidn en la parte designada como EXPORT TABLE,
en6stasecciónseencuentrauna
lista de las funcionesquehansidoexportadasparasuuso
público, 6sta lista cuenta con tres columnas: Ordinal, Entry Point y Name. El primero es el número
de la funcibn dentro del c6digo de la librería y corresponde a su posicidn ordinal, es decir, si es la
primera,lasegunda,latercera,etc.,
los númerosde6stacolumnaestanenhexadecimal.La
segunda columna corresponde a su mapeo en memoria una vez cargada la librería; por lo general
unaDLLcontieneunvalorhexadecimalqueindicaladireccibndememoriapreferidaparaser
cargada,comosepuedeveren
el parámetro Base of Code, quetambi6nsemuestraenel
Quikview del archivo, pero, sin embargo, es posible que otra DLL se cargue primero en esa base
de memoria y por lo tanto nuestra DLL no pueda cargarse en su direccibn base predeterminada,
por Io que se requiere que la DLL sea
Redireccionable (Relocatable), y en efecto lo es, lo cual
significa que si no puede cargarse en su base predeterminada puede redireccionarse en otra base
de memoria y todos los mapeos de memoria de las funciones cambiaran de acuerdo a la nueva
base. La tercera columna corresponde al nombre de la funcibn que es como debe importarse
o
llamarse en el cbdigo que las utiliza. Algunas de las funciones m& importantes que pueden verse
aquí son por ejemplo: SQLAIlocConnect, SQLAllocEnv, SQLAllocStmt, entre otras; &stas y algunas
más, serán estudiadas a fondo enlos capítulos siguientes.
En el Ap6ndice A se muestra el listado de cbdigo en el que se declaranlas funciones de la librería
de ODBC para su uso con Visual Basic. En 61 se pueden ver los argumentos que requieren cada
una de ellas, así como los valores que regresan estas funciones.
3
Conexión ODBC a bases de datos
Ya hemosvistocualeslanaturaleza
del ODBC,laquepuederesumirseenunconjuntode
funcionesencapsuladasenunalibreríadeenlacedinsmicollamadaODBC32.DLL.Enéste
capítulo entraremos en detalle en el uso de las llamadas a la API relacionadas con la conexion a
las bases de datos,el manejo de erroresy la creación de conexiones múltiples.
3.1 Primero: Se requiere un handle de ambiente
Antesdequeunaaplicaciónpuedautilizarcualquierade
las funcionesODBC, éSta debede
inicializar la interfaz de ODBC y obtener un handle de ambiente con la funcibn
SQLAllocEnv:
Dim rc as integer, henv as Long
rc = SQLAllocEnv(henv)
Si SQLAllocEnv regresaSQL-SUCCESS, el ODBCdrivermanagerestainicializado,
y seha
reservado espacio en memoria para almacenar informacion acerca
del ambiente. Si por el contrario
la función falla, los DLLs de ODBC no se inicializaron correctamente. Solo se necesita ejecutar
SQLAllocEnv unavezyaque
el handledeambientequeseobtieneescapazdesoportar
conexiones múltiples a fuentes de datos.
La función SQLAllocEnv ()
Propósito
SQLAllocEnv() coloca en memoria un handle de ambientey los recursos asociados para éste. Una
aplicacion debe de llamar primero a dsta funcidn antes que a SQLAllocConnect() o que cualquier
15
16
otra funci6n de ODBC CLI. El valor henv es pasado despues a todas las funciones que requieran
un handle de ambiente como entrada.
Sintaxis
SQLRETURN SQLAllocEnv (SQLHENV *phenv);
Argumentos de la función
Tabla 1. Argumentos de SQLAllocEnv.
Argumento
Tipo
dato de
Uso
~~~
Descripci&n
~
SQLHENV
Phenv
Apuntador
al Salida
ambiente
Comentarios
Sólo puedehaberunambienteactivoaunmismotiempopor
aplicaci6n. Cualquierllamada
posterior a SQLAllocEnv() regresael handle de ambiente existente.
Se debe llamar a SQLFreeEnvO por cada SQLAllocEnv() que se haya ejecutado con Bxito para
liberar los recursos asociados al handle.
Códigos de retorno
SQL-SUCCESS
SQL-ERROR
Si se regresa SQL-ERROR y phenv es igual a SQL-NULL-HENV, entonces no se puede llamar a
SQLErrorO porque no hay un handle conel cual asociar informaci6n de diagn6stico adicional.
Si el c6digoderetornoes
SQL-ERROR y el apuntador al handledeambientenoesiguala
SQL-NULL-HENV,entonces
el handleesun
handlerestringido. Estosignificaque
el handle
o
solamente puede ser usado en una llamada a SQLErrorO para obtener mas informaci6n del error,
por SQLFreeEnvO.
3.2 Segundo: Se requiere un handle de conexión
Antes de que una aplicacidn pueda conectarse a un controlador, Bsta debe obtener un handle para
laconexión.Lafunci6n
SQLAllocConnect seusaparaesteprop6sit0,comosemuestraen
el
siguiente ejemplo:
Dim rc as Integer, hdbc as Long
rc = SQLAllocConnect(ByVal henv, hdbc)
Si lafunci6n SQLAllocConnect regresaSQL-SUCCESS,se
tiene memoriareservadaparaun
handle de conexi6n. Si esta funci6n falla, se puede usar la funci6n
SQLError para determinar la
causa. Se debe establecer un handle de conexi6n para cada conexidn que se abra.
17
La función SQLAllocConnect ()
Propósito
SQLAllocConnect() coloca en memoria un handle de conexibn y los recursos asociados para &te
dentro del ambiente identificado porel handle de ambiente de entrada. SQLGetlnfo() conf/nfoType
puesto a SQL-ACTIVE-CONNECTIONS, proporciona
el número de conexiones que pueden ser
almacenadas a un mismo tiempo. Se debe llamar a SQLAllocEnv() antes que
&aa función.
Sintaxis
SQLRETURN SQLAllocConnect (SQLHENV henv, SQLHDBC *phdbc);
Argumentos de la función
Tabla 2. Argumentos de SQLAllocConnect.
Tipo de dato
Entrada
SQLHENV
Salida
*
SQLHDBC
Argumento
uso
Descripción
Henv
Handle de ambiente
Phdbc
Apuntador a la conexi6n
Comentarios
El handle de conexibn de salida es usado por el ODBC CLI para referenciar a toda la informacibn
relacionada con la conexibn, incluyendo informacibn del status general de la misma, estado de la
transacción, e informacibn delos errores.
Si el apuntador al handle de conexibn(phdbc)apunta a un handle de conexibn valido obtenido por
SQLA//ocConnect(),el valor original se sobreescribe en cada llamada la
a funcibn.
Códigos de retorno
0
SQL-SUCCESS
SQL-ERROR
0
SQL-INVALID-HANDLE
Si se regresa SQL-ERROR,
el argumento phdbc es puesto a SQL-NULL-HDBC. La aplicacibn
debeentoncesllamaralafuncibn
SQL€rror() con el handledeambiente
(henv) y con los
argumentos hdbc y hstmt puestos a SQL-NULL-HDBC y SQL-NULL-HSTMT respectivamente,
para el chequeo de errores.
3.3 Tercero: Se procede a la conexión
Una vez que los handles de ambiente y de conexibn han sido obtenidos,el cbdigo puede abrir una
o mds conexiones a bases de datos remotas usando un handle de conexibn
diferente para cada
conexibn. AI trabajar con algunas bases de datos, puede ser necesario abrir mas de una conexibn
para soportar operaciones simultdneas de consultas múltiples o actualizacibn-pero no todas las
18
bases de datos requieren de conexiones adicionales para operaciones múltiples. Es mejor crear
varios handles de sentenciao instrucci6n enuna sola conexibn que crear múltiples conexiones con
una solasentencia.Paradeterminar
si el controladordelabasededatossoportamúltiples
sentencias activas en una sola conexi6n se utiliza
la funci6n SQLGetlnfo.
Requisitos para la conexión
El c6digo debe proveerlos siguientes argumentos para establecer
una conexi6n:
0
0
Un handle de ambiente vdlido creado por SQLAllocEnv.
Un handle de conexi6n vdlido creado por SQLAllocConnect.
Un nombre de fuente de datos registrado que corresponde a la entrada DSN en el archivo
0DBC.ini o en el registro del sistema.
Un ID de usuario vdlido (opcional), el cual es el ID de acceso o nombre de la cuenta usado
para acceder a la fuente
de datos.
Un password o contrasetia valida (opcional) que correspondeal ID del usuario.
Cualesquiera otros parametros opcionales que proporcionen informaci6n
la cual el controlador seleccionarduna base de datos específica.
al controlador, con
Creando el nombre de fuente de datos(DSN) de ODBC
Cuando se abre una conexi6n a cualquier base de datos
o servidor de base de datos remoto con la
API de ODBC, se hace referencia a un nombre de fuente de datos o Data Source Name (DSN).
Aunque es posible crear DSNs en el c6digo con
la funci6n de ODBC ConfigDSN, la forma mas
sencilla de crear o modificar un DSN es usandoel programa Administrador del ODBCdel Panel de
Control.
La informaci6n del DSN se almacena en el archivo 0DBC.ini en los sistemas de 16 bits y en el
registro del sistema en los sistemas de 32 bits. Si se tienen aplicaciones tanto de 16 bits comode
32 bits corriendo en un sistema operativo
de32bits,talcomoWindowsNT
o Windows 95, se
deben establecer las entradas para el DSN para ambos casos, para el archivo 0DBC.ini y para el
registro del sistema.
Tres maneras de culminarla conexión
Para establecer la conexibn, se pueden usar una de las tres funciones de la API de ODBC para
pasar los parametros necesariosal manejador de controladores ODBC:
SQLConnect acepta un nombre de fuente de datos DSN, ID del usuario, y password como
argumentos. SQLConnect cambia el estado
de
hDbc
conectado
a
y regresa
SQL-SUCCESS, SQL-SUCCESS-WITH-INFO
o SQL-ERROR.
SQLDriverConnect acepta una cadena de conexidn similar ala de la propiedad Connect del
control Visual Basic Data, excepto que no empieza conel pardmetro "ODBC;", y no soporta
el pardmetro"TIMEOUT".Paraestablecer
el timeoutde la conexi6n ODBC seutilizala
funcidn SQLSetConnectionOption. Si no se da suficiente informacidn con la cadena, uno o
mas didlogos se despliegan para obtener los pardrnetros faltantes o invdlidos. Esta funci6n
19
e
regresa SQL-ERROR si el usuario hace click en el botón Cancelar o si el manejador no se
puede conectar por otras razones.
SQLBrowseConnect soporta un metodo
iterativo
para
determinar
los controladores
disponibles, fuentes de datos y otros pardmetros. La aplicación escoger& de las fuentes de
datos disponibles.
En éste trabajo sólo se describird a la función SQLConnect por ser la mas sencilla de todas y
porque es una de las funcionesdel núcleo primario de funciones de
la API de ODBC. Las otras dos
funciones: SQLDriverConnect y SQLBrowseConnect, sonextensionesde
nivel 1 o nivel 2 al
WOpen and SQL Access Group Call Level lnterface y no siempre son soportadas por todos los
drivers.Paradeterminar
si undriversoportaunafunciónespecífica,seutiliza
la función
SQLGetFunctions.
La función SQLConnect ()
Propósito
SQLConnectO estableceunaconexióna
una basededatosdestino.Laaplicacióndebe
proporcionar una base de datos destino, y opcionalmente un nombre de usuario y una cadena de
autentificación o password
correspondiente
al nombre
de
usuario.
Se
debe
llamar
a
SQLAllocConnect() antes que a ésta función y a su vez esta función debe ser llamada antes que
SQLAllocStmt().
Sintaxis
SQLRETURN
SQLConnect
(SQLHDBC
hdbc,
SQLCHAR
SQLSMALLINT
SQLCHAR
SQLSMALLINT
SQLCHAR
SQLSMALLINT
*szDSN,
cbDSN,
*szUID,
cbUID,
*szAuthStr,
cbAuthStr);
Argumentos de la función
Tabla 3. Argumentos de SQLConnect.
Tipo Argumento
del dato
uso
Descripci&n
Entrada
SQLHDBC
Entrada
*
SQLCHAR
Hdbc
SQLSMALLINT
SQLCHAR *
CbDSN
SzUID
Handle de conexión
Fuente de datos:El nombre o alias de la base
de datos.
Entrada
Longitud
argumento
del
szDSN
Entrada
ldentificador
usuario
del
SQLSMALLINT
CbUlD
Entrada
Longitud
argumento
del
szUlD
SzDSN
SQLCHAR
SzAuthStr
Entrada
Cadena
autentificacion
de
(password)
SQLSMALLINT
CbAuthStr
Entrada
Longitud
argumento
del
szAuthStr
Comentarios
Es posible definir varias características (opciones) para
función SQLSetConnectOption().
la conexión en la aplicación usando la
20
Losargumentosdelongituden
SQLConnect() (cbDSN, cbUID,cbAothSfr) puedenserpuestos
como las longitudes actuales delos datos asociados. No se incluyenlos caracteres de terminaci6n
de nulo. Se puede usar SQL-NTS en los argumentos de longitud para indicar que
el dato asociado
esta terminadoen nulo.
Los espacios a la izquierda o a la derecha en los valores de szDSN y SZUID son eliminados a
menos que estos se encuentren enmarcados en comillas
o comillas dobles.
Códigos de retorno
SQL-SUCCESS
SQL-SUCCESS-WITH-INFO
SQL-ERROR
SQL-INVALID-HANDLE
Ejemplo C
Listado 2. Conexión a una fuente de datos en C.
int connect(SQLHENV henv, SQLHDBC * hdbc)
SQLRETURN rc;
SQLCHAR server[MAX-DSN-LENGTH t 11,
uid [MAX-UID-LENGTH+ 11 ,
pwd [MAX-PWD-LENGTH+ 1] ;
{
printf
("Servidor: ; \n")
gets ( (char * ) server);
printf
("Usuario: ; \n")
gets ( (char * ) uid) ;
printf
("Password: ; \n")
gets ( (char * ) pwd) ;
SQLAllocConnect(henv, hdbc);/ * establece un handlede conexión * /
rc = SQLConnect (*hdbc, server,
SQL-NTS, uid, SQL- NTS, pwd,SQL-NTS);
if (rc ! = SQL-SUCCESS)
printf("Error al intentar conectara la base de datos\n");
return (SQL-ERROR);
1 else [
printf ("Conexión exitosa\n")
;
return (SQL-SUCCESS);
1
Ejemplo VB
Listado 3. Conexión a una fuente de datos en VisualBasic.
Dim
Dim
Dim
Dim
Dim
rc as Integer
hdbc as Long
DSN as String
UID as String
PWD as String
'Inicializa el handle
de conexión
rc = SQLAllocConnect(henv, hdbc)
DSN
=
"Nombre Base"
21
UID
PWD
=
=
"Tendo"
"Kasumi"
rc = SQLConnect (hdbc,
DSN, Len(DSN), UID, Len(UID), PWD, Len(PWD)
)
if rc <> SQL-SUCCESS Then
MsgBox "Error al intentar conectar
a la basede datos''
Else
MsgBox "Conexión exitosa"
End If
3.4 Ultimo: Se liberan los recursos usados
Hasta ahora hemos visto los pasos necesarios para realizar una conexión a una base de datos, a
saber son: obtener el handle de ambiente, obtenerel handle de conexión y realizar la conexiónen
sí. Después de esto se pueden hacer todas las consultas que se necesiten a la base de datos y
procesar la información obtenida. Pero después de esto que sigue?
No es bueno dejar conexiones
abiertas a diestra y siniestra, pues afecta
al rendimiento del motor de base de datos, toda conexión
abierta es un recurso en el servidor que implica memoria y tiempo de procesamiento, a mayor
número de procesos, menor tiempo de atención para cada uno.
Es por ello que se deben liberar
los
recursos asociados a una conexión
unavez que se obtuvo y procesó la información deseada,
cerrandolasconexionesexistentes.Laformadehacerlo
en VisualBasicseejemplificaen
el
fragmento de código que sigue:
Dim rc as Integer
rc = SQLDisconnect(hdbc) 'Cierra la conexión a la BD
rc = SQLFreeConnect(hdbc) 'Libera el handlede conexión y l o s recursos
y los recursos
rc = SQLFreeEnv (henv) 'Libera el handle de ambiente
La función SQLDisconnect, cierra la conexión entreel servidor y la maquina cliente, pero es posible
establecer conexión otra vez conla función SQLConnect usando el mismo handle de conexión, sin
embargo, la función SQLfreeConnect libera al handle de conexión y ya no es posible usarlo para
abrir otra conexión, a menos que sea establecido otra vezcon SQLAllocConnect, lo mismo sucede
con el handle de ambiente, con SQLfreeEnv se libera al handle y para poder obtener otro handle
utilizable se debe llamar SQLAllocEnv.
a
La función SQLDisconnect ()
Propósito
SQLDisconnect() cierra la conexión a una base de datos asociada
con un handle de conexión.
Después de llamar a 6sta función, se puede llamar a SQLConnect() para conectar a otra base de
datos o a la misma, o llamar a SQLFreeConnectO para liberarlos recursos del handlede conexión.
Sintaxis
SQLRETURN SQLDisconnect (SQLHDBC hdbc);
n de
22
Argumentos de la función
Tabla 4. Argumentos de SQLDisconnect.
Tino de dato
Hdbc
Araumento
SQLHDBC
uso
DeSCriRCidn
Entrada
conexión
Handle
de
Comentarios
Si una aplicación llama a SQLDisconnect antes de que se hayan liberado todos
los handles de
sentencia asociados con la conexidn, ODBC los libera despubs de que realiza la desconexión de la
base de datoscon bxito.
Si se regresa SQL-SUCCESS-WITH-INFO, esto implica que aunque
la desconexibn de la base
de datos fue exitosa, setiene informacibn de implementacibno de un error. Por ejemplo:
Se encontro un problema al hacer la limpieza despues de la desconexibn, o,
Si no existe una conexidn actual debido a un evento independiente de la aplicacibn (como
una falla en la comunicacibn).
Despues de un exitoso SQLDisconnect(), la aplicacibn puede reusar hdbc para hacer otro llamado
a SQLConnect().
Códigos de retorno
0
SQL-SUCCESS
SQL-SUCCESS-WITH-INFO
SQL-ERROR
0
SQL-INVALID-HANDLE
La función SQLFreeConnect()
Propósito
SQLFreeConnectO invalida y libera el handle de conexibn. Todos los recursos asociados al ODBC
CLI con el handle de conexibn son liberados. Se debe llamar a SQLDisconnect() antes que a esta
funcibn. Se puede llamar a SQLFreeEnvO para continuar con la terminacibn del programa,
o a
SQLAllocHandle(), para obtener un nuevo handle de conexibn.
Sintaxis
SQLRETURN SQLFreeConnect (SQLHDBC hdbc);
Argumentos de la función
Tabla 5. Argumentos de SQLFreeConnect.
TipoArgumento
de dato
Handle
Entrada Hdbc
SQLHDBC
Uso
Descripción
23
Comentarios
Si esta funci6n se llama cuando existe aún una conexi6n abierta, la funci6n regresa SQL-ERROR,
y el handle de conexi6n permanece valido.
Códigos de retorno
SQL-SUCCESS
SQL-ERROR
0
SQL-INVALID-HANDLE
La función SQLFreeEnv ()
Propósito
SQLFreeEnvO invalida y libera el handle de ambiente. Todoslos recursos del ODBC CLI asociados
con el handle de ambiente son liberados. Se debe llamar a SQLFreeConnectO antes que a
M a
funci6n. Esta funci6n esla última que debe llamar una aplicacidn antes de terminar.
Sintaxis
SQLRETURN S Q L F r e e E n v (SQLHENV h e n v ) ;
Argumentos de la función
Tabla 6. Argumentos de SQLFreeEnv.
~~~
Tipo de Argumento
dato
Uso
Descripci6n
Handle
Entrada henv
SQLHENV
Comentarios
Si ésta funci6n es llamada cuando aún existe un handle de conexi6n vAlido, la funci6n regresa
SQL-ERROR, y el handle de ambiente permanece valido.
Códigos de retorno
SQL-SUCCESS
SQL-ERROR
0
SQL-INVALID-HANDLE
3.5 Formato básico de una aplicación ODBC
Como se ya se ha visto a
lo largo de este capítulo, la creaci6n de una aplicaci6n con la API de
ODBC sigue cierto lineamiento en cuanto al orden de llamada de las funciones de la librería de
ODBC. Toda aplicaci6n queutilice las funciones de la API debe seguir este formato, desde obtener
24
unhandledeambientehastalaliberacidndelmismo.
Es imprescindibletenerencuentaque
desconectar una fuente de datos no significa que el handle de conexi6n haya sido liberado, sino
que ese mismo handle puede ser utilizado para establecer otra conexi6n con una fuente de datos
distinta, mientras no se libere con la funcibn
SQLFreeConnect.
Se tienepues,unformatodefinido
en la partedelaccesoadatosdeunaaplicaci6nque
usa
ODBC, este consta de la obtenci6n de los handles necesarios, el procesamiento de sentencias de
SQL y la liberaci6n de los recursos despues de hacerse las consultas. Como se muestra
en la
Figura 4, la parte de las consultas puede constarde varios ciclos de procesamiento de sentencias
de SQL y de manejo de resultados, este
ciclo puede durar tanto tiempo como
lo disponga un
usuario o según sea la 16gica de la aplicaci6n.
Se Obtienen los
handles necesarios
para la conexidn y
se establece la
misma
Se procesan las
consultas mediante
un handle de
sentencia como se
vera en el siguiente
capítulo
Se desconecta de la
fuente y se liberan
los handles de
conexidn
SQLAllocEnv
SQLAllocConnect
SQLConnect
SQLAllocStmt
Procesar sentencia SQL
Obtener resultados
SQLFreeStmt
SQLFreeEnv
Figura 4. Formato básicode una aplicación ODBC.
En el siguiente capítulo se revisa lo concerniente a las consultas. La parte de procesamiento de
sentencias de SQL y de manejo de resultados viene ligadoun
a handle mas,el cual como se podra
suponer, reserva recursos de memoria para las consultas que se envian a la base de datos. Los
resultados que se obtienen se procesan según las necesidades de la aplicacidn en particular. Por
supuestoque al satisfacer todas las consultas el handledesentenciadebeserliberadoen
el
código con SQLFreeStmt como buena practica de programacibn, aunque esto es opcional, pues
como ya se vio antes, la funci6n SQLDisconnect en el bloque de liberaci6n de recursos los libera
en forma autom8tica.
25
3.6 Conexiones múltiples y manejo de errores
Una aplicaci6n no necesariamente tiene que estar atada a una sola conexibn, una vez obtenido el
handle de ambiente hem, se pueden tener todos los handles de conexi6n hdbc que se deseen y
que los recursos de memoria permitan. Un handle de ambiente puede soportar varios handles de
conexibn, así como un handle de conexi6n puede soportar varios handles de sentencia
hsfmt. El
Listado 4 muestra c6mo se realiza la conexion a dos fuentes de datosdistintas utilizando el mismo
handle de ambiente, cada conexi6n se hace dentro de una funcidn llamada conect, a la cual se le
pasan como argumentos el handle de ambiente por valor,
y por referencia una variable de tipo
SQLHDBC la cual contendrael valor del handle de conexi6n obtenido para esa fuente de datos. La
parte de creaci6n de sentencias para consultas se omite por simplicidad.
Listado 4. Ejemplo de conexidn a dos fuentesde datos distintas enC.
........................................................
**
* * Conexión a dos fuentes de datos
**
* * Funciones usadas:
**
**
SQLAllocConnect
SQLDisconnect
**
SQLAllocEnv
SQLFreeConnect
**
SQLConnect
SQLFreeEnv
**
.........................................................
#include <stdio.h>
#include <stdlib.h>
/ * Declaraciones de l o s tipos de datos y de las funciones ODBC* /
#include "sqlcli. h"
int connect(SQLHENV henv, SQLHDBC * hdbc);
#define
#define
#define
#define
MAX-DSN-LENGTH
18
MAX-UID-LENGTH
10
MAX PWD LENGTH 10
MAXICONNECTIONS5
int main()
(
SQLHENV henv; / * Declara la variable de ambiente
*/
SQLHDBC hdbc[MAX
-CONNECTIONS]; / * Arreglo de variables de conexión * /
/ * Obtiene un handle de ambiente * /
SQLAllocEnv (&henv);
/ * Conecta con la primer fuente de datos * /
connect (henv, &hdbc [O] ) ;
/ * Conecta con la segunda fuente de datos * /
connect (henv, &hdbc [ 11 ) ;
/********
Inicia el procesamiento de resultados * * * * * * * * * /
/ * Obtener handle de sentencia, ejecutar sentencia, etc. * /
/ * En esta parte van las consultas y la obtención de
*/
/ * resultados
*/
/********
Finaliza el procesamiento de resultados * * * * * * * /
printf
("\nDesconectando
. . . . . \n");
26
SQLDisconnect (hdbc[Ol) ; / *
SQLDisconnect (hdbcrl])
; /*
SQLFreeConnect (hdbc
[O]) ; / *
SQLFreeConnect (hdbc[l]
) ; /*
SQLFreeEnv(henv);
/*
Desconectando la primer fuente
de datos * /
Desconectando la segunda fuente
de datos * /
Liberamos el primer handlede conexión * /
Liberamos el segundo handlede conexión * /
Liberamos el handle de ambiente * /
.....................................................................
**
connect - Pidedatos de conexión y realizalaconexi6n
**
.....................................................................
int connect(SQLHENV henv, SQLHDBC* hdbc)
SQLRETURN
rc;
SQLCHARserver
SQLCHAR
SQLSMALLINT
{
[MAX-DSN-LENGTH + 11,
uid[MAX-UID-LENGTH + 11,
pwd[MAX-PWD-LENGTH + 11;
buffer[255];
outlen;
printf ("Teclear nombre del servidor
->\n");
gets ( (char * ) server);
printf ("Teclear nombre del usuario -->\n")
;
gets ((char* ) uid);
printf("Tec1ear clave del usuario --->\n");
* ) pwd) ;
gets( (char
SQLAllocConnect(henv, hdbc);/ * obtiene un handle de conexión * /
/ * SQL-NTS indica que las cadenas pasadas finalizan con
nulo * /
rc = SQLConnect (*hdbc, server,
SQL-NTS, uid, SQL-NTS, pwd, SQL-NTS) ;
if (rc ! = SQL SUCCESS) {
printf ("ErTor
al intentar conectara la base de datos\n")
;
return (SQL-ERROR);
) else {
printf("La conexiónse realizó con éxito\n");
return (SQL-SUCCESS);
1
1
Observese del código anterior, que dado un handle de ambiente henv, se pueden hacer todas las
conexiones que se deseen,el Único requisito es declarar una variable distinta para cada handle
de
conexi6n hdbc que se requiera; en el caso anterior se utiliz6 un arreglo de tipo SQLHDBC para
almacenar los handlesdeconexibnobtenidos,
lo cual esunasoluci6nadecuadacuando
no
conocemos el númerodeconexionesquesevanaestablecer.Porsupuestoquetodaslas
conexiones hechas deben cerrarse y tambien los handles de conexidn deben liberarse, por lo que
se debe llamar a las funciones SQLDisconnect y SQLFreeConnect por cada conexi6n realizada, la
ventaja de declarar un arreglo para los handles de conexibn es que la desconexi6n y liberacidn de
recursos se puede hacer dentrode un ciclo For, que resulta muy sencillo de implementar.
Manejo de errores
Ya se ha visto que todas las funciones de ODBC hasta ahora tratadas, al ejecutarse, regresan un
valor que indica si la funci6n se ejecut6 bien o no, este valor es un c6digo de retorno o Return
Code, y cada funci6n de ODBC cuenta con un conjunto fijo de los cddigos de retorno que puede
27
regresar. Debido a 6sta caracteristica de las funciones de ODBC en sus códigos de retorno, es
posible hacer un manejo sencillo de errores
al saber que códigos de retorno podemos esperar,
para ello se pueden usar bloques If, Then o bloques Select, Case o Switch según sea el caso. Un
lo podemos ver en ellistado de código arriba presentado
ejemplo de éste manejo simple de errores
del cual extraemos la parte
de interés para su estudio enel siguiente fragmento.
rc = SQLConnect(*hdbc, server, SQL-NTS, uid, SQL- NTS, pwd, SQL-NTS);
if (rc ! = SQL SUCCESS) {
printf ("Error
al intentar conectar la
a base de datos\n")
;
return (SQL-ERROR);
1 else {
printf("La conexión se realizó con éxito\n");
return (SQL-SUCCESS);
1
El bloque If, Then prueba para el Return Code(rc) SQL-SUCCESS, si el rc no es SQL-SUCCESS,
se da por omisión que entonces es SQL-ERROR, pues se ha dado por entendido que no puede
ser SQL-INVALID-HANDLE que es
el código de retorno restante para
la función SQLConnect.
Para hacer una prueba exhaustiva delos códigos de retorno usaríamos un bloqueSwitch, como se
muestra en el siguiente fragmento de código C:
rc = SQLConnect (*hdbc, server, SQL
-NTS, uid, SQL-NTS, pwd,SQL-NTS) ;
swicth (rc) {
case SQL-ERROR:
printf("Error al intentar conectar a la base
de datos\n");
break;
case SQL-SUCCESS:
printf("La conexión se realizó con éxito\n");
break;
case SQL-INVALID HANDLE:
;
printf ("El handle proporcionado es inválido\n")
1
De ésta forma se agotan todas las posibilidades para una función en particular,
lo que permite
hacerunmanejom&precisode
los errores.Conestointroducimoslafuncióndemanejode
errores de la API de ODBC,
la función SQLError. La función SQLError proporciona información
sobre errores y advertencias (warnings),6sta función debe llamarse en cualquier caso en que el
y para
código
de
retorno
no
sea
SQL-SUCCESS,
especialmente
para
SQL-ERROR
SQL-SUCCESS-WITH-INFO.
La función SQLError ()
Propbito
SQLError() proporciona la información de diagnóstico asociada con la llamada mas reciente a una
función del CLI para un handle de sentencia, conexión
o ambiente en particular. La información
consiste de un SQLSTATE normalizado, el código de error nativo, y de un mensaje en texto. Se
debe
llamar
a
SQLError()
después
de
recibir
un
código
de
retorno
de
SQL-ERROR o
SQL-SUCCESS-WITH-INFO en la llamada a otra función.
28
Sintaxis
SQLRETURN SQLError (SQLHENV
SQLHDBC
SQLHSTMT
SQLCHAR
SQLINTEGER
SQLCHAR
SQLSMALLINT
SQLSMALLINT
henv,
hdbc ,
hs tmt ,
*szSqlState,
*pfNativeError,
*szErrorMsg,
cbErrorMsgMax,
*pcbErrorMsg);
Argumentos de la función
Tabla 7. Argumentos de SQLError.
Tipo de dato
Argumento
uso
Descripción
SQLHENV
henv
Entrada
SQLHDBC
hdbc
Entrada
Handle de ambiente. Para obtener
la información de
diagnóstico asociada a un ambiente, se pasa un
handle de ambiente válido. Poner hdbc y hstmt a
SQL-NULL-HDBC y SQL-NULL-HSTMT
respectivamente.
Handle de conexión ala base de datos. Para obtener
la información de diagnóstico asociada con una
conexión, se pasa un handle de conexión válido,sey
pone hstmt aSQL-NULL-HSTMT. El argumento henv
es ignorado.
Handle de sentencia. Para obtener
la información de
diagnóstico asociada con una sentencia, se pasa un
handle de sentencia válido. Los argumentos henv
y
hdbc son ignorados.
SQLSTATE es una cadena de5 caracteres terminada
con el caracter nulo. Los primeros2 caracteres indican
la clase del error;los siguientes 3 indican la subclase.
Los valores corresponden directamente los
a valores
de SQLSTATE definidos enla WOpen SQL CAE
specification y en la ODBC specification, aumentados
con valores de SQLSTATE específicos de
IBM y del
producto de base de datos.
Código de error nativo. Código de error generado por
el manejador de base de datosutilizado. Si el error es
generado porel CLI y no porel manejador de base de
datos (DBMS), éste campoes puesto a-99999.
Apuntador al buffero cadena que contendráel
mensaje o texto con la descripción del problema.
Máxima (esto es, la reservada) longitud del buffer
szErrorMsg. La longitud recomendada para reservar
es SQL-MAX-MESSAGE-LENGTH + 1.
Entrada
hstmtSQLHSTMT
SQLCHAR *
szSqlState
Salida
SQLINTEGER *
pfNativeError
Salida
SQLCHAR *
szErrorMsg
Salida
SQLSMALLINT
cbErrorMsgMax
Entrada
SQLSMALLINT
pcbErrorMsg
Salida
Apuntador al número total de bytes disponibles enel
buffer de salida szErrorMsg (longitud de
la cadena de
descripción del error). Este no incluye
al caracter
terminador nulo.
Comentarios
Los SQLSTATEs son definidos por la WOPEN SQL CAE y la WOpen SQL CLI, aumentados con
valores específicos de IBM y del producto de base de datos que se maneje.
29
Para obtener informaci6nde diagn6stico asociada con:
El ambiente, pasar un handle de ambiente valido, y poner hdbc y hstmt a SQL-NULL-HDBC
y SQL-NULL-HSTMT respectivamente.
Una conexion, pasar un handle de conexibn valido, y poner hstmt a SQL-NULL-HSTMT.
argumento henv es ignorado.
Una sentencia,pasar
ignorados.
un handledesentenciavalido.
El
Los argumentos henv y hdbc son
Si la informaci6n de diagndstico generada por alguna funci6n del CLI no es obtenida antes de
que
se llame a cualquier otra funcibn que no sea SQLError() con el mismo handle, la informaci6n para
la funci6n previamente llamada se pierde. Esto ocurre aún
si nose genera informaci6n para la
siguiente funci6n que se llama.
Para evitar el truncamiento del mensaje de error, se declara la longitud
del buffer de salida de:
SQL-MAX-MESSAGE-LENGTH + 1. El mensaje nuncasera mas largo que esto.
Códigos de retorno
SQL-ERROR
SQL-INVALID-HANDLE
SQL-NO-DATA-FOUND
SQL-SUCCESS
Recuperando mensajes de error
Si una funci6n que no sea SQLError regresa SQL-ERROR o SQL-SUCCESS-WITH-INFO, una
aplicación puede entonces llamar a
SQLError para obtener informacibn del error. La aplicaci6n
puede necesitar llamar aSQLError mas de una vez para recuperar todoslos mensajes de errorde
una función, pues una funci6n puede generar varios mensajes de error. Cuando la aplicaci6n llama
a otra funci6n diferente.los mensajes de error para la funcidn previa son eliminados.
Se puedetenerinformacidnadicionaldeerrores
o deestadoprovenientedealguna
de las
siguientes fuentes: De una funci6n de ODBC, indicando que se detect6 un error de programacibn.
O deunafuente
de datos,indicandoqueocurri6
un errordurante el procesamiento deuna
sentencia.
La información dada por SQLError esta en el mismo formato que la de la especificacibn para el
SQLSTATEen el X/Open and SQLAccessGroupSQLCAEspecification
(1992). Notar quela
funci6n SQLError nunca regresa información de error para
sí misma.
Mensajes de error de ODBC
ODBC define una arquitectura por capas para conectar una aplicacibn con una fuente de datos.
En
su forma mas simple, una conexi6n ODBC requiere de dos componentes: el Driver Manager y un
driver. Una conexi6n mas compleja podría incluir mas componentes: el Driver Manager, un cierto
número de drivers, y un cierto número (posiblemente diferente) de DBMS’s. La conexi6n podría ser
a traves de varias plataformas de computaci6n y de sistemas operativos y usar una variedad de
protocolos de red.
30
Conforme
la
complejidad
de
una
conexión
de
ODBC
se
incrementa,
es
mas
importante
proporcionarmensajesdeerrorconsistentes
y completospara la aplicacibn, los usuarios, y el
personaldesoporte.Losmensajesdeerrorno
sblo debenexplicar el error,tambikndeben
proporcionarlaidentidad
del componenteenelcualocurrib.Laidentidad
del componentees
particularmente importante para el personal de soporte cuando una aplicacibn utiliza componentes
de ODBC dedistintas compaiíías. Puesto queSQLError no regresa la identidad del componente en
el cual ocurrió el error, esta informaci6n debe estar incrustada en el texto del mensaje de error.
Formato del mensaje de error
Los mensajes deerror proporcionados por SQLError vienen de dos direcciones: fuentes de datos
y
componentes en una conexibn ODBC. Típicamente,las fuentes de datos no soportan directamente
ODBC. Consecuentemente, si un componente en una conexibn de ODBC recibe un mensaje de
error de una fuente de datos, este debe identificar la fuente de datos como la fuente del error. Debe
ademas de identificarse a sí mismo comoel componente que recibi6 el error.
Si la fuente del error es el componente en si, el mensaje de error debe describirlo así. Por eso, el
mensaje de error dado por SQLError tiene dos formatos diferentes: uno para errores que ocurren
en una fuente de datos y otro para errores que ocurren en otros componentes de una conexibn de
ODBC.
Para errores que no ocurren en
la fuente de datos,el texto tiene el formato:
[identificacibn de/ proveedo~[identificacibn
del componente deODBC]
texto suministradopor el componente
Para errores que ocurren en una fuente de datos,
el texto tiene el formato:
[identificacibn del proveedor][identificaci6n de/ componente de ODBC]
[identificacibn de /afuente de datos] texto suministradopor la fuente de datos
La siguientetabla muestra el significado de cada elemento.
Tabla 8. Componentes del mensaje de error de
ODBC.
Elemento
Significado
identificación
del
proveedor
Identifica
vendedor
al
o proveedor
del
componente
que
en
el
ocurrió el erroro que recibió el error directamente de la fuente
de datos.
identificacióndelcomponentede ODBC
Identificaelcomponente en el queocurrióelerror o que
recibió el error directamentede la fuente de datos.
identificaciónde la fuentededatos
Identificalafuentededatos.Paradriversdeunnivel,éstees
típicamente un identificador detipo o formato de archivo, tal
como Xbase’. Para drivers multinivel, éste es
el nombre del
DBMS.
Generadopor el componentede ODBC.
Generadoporlafuentededatos.
textosuministrado por elcomponente
textosuministrado por la fuente de datos
1. En éste caso,el driver actúa comotal y como fuente de datos.
Note que los brackets (0) se incluyen enel texto del error; no indican elementos opcionales.
31
3.7 Los códigos de retorno y los tipos de datos
Cuando una aplicaci6n llama a una funci6n
de ODBC, el driver ejecuta la funci6n y regresa un
&digo de retorno predefinido. Estos c6digos de retorno indican estados de dxito, advertencia
o
falla en la funci6n. La Tabla
9 define los c6digos de retorno para las funciones de ODBC.
Tabla 9. Códigos de retorno delas funciones deODBC.
~
retorno
Código
de
Valor
Descripción
SQL-SUCCESS
O
La
función
se
completó
satisfactoriamente,
información adicionaldel SQLSTATE.
SQL-SUCCESS-WITH-INFO
1
La función
completó
se satisfactoriamente,
con
una
advertencia u otra información.Usar SQLErrorO para obtener
el SQLSTATE e informacióndel error.
SQL-NO-DATA-FOUND
1O0
La
función
se
ejecutó
bien,
pero
no se
encontró
información
en el conjunto de resultados, pues se han leido todas las
lineas y se llegó al final del mismo.
SQL-ERROR
-1
SQL-INVALID-HANDLE
-2
función
La falló
debido
handle
una inválido
(ambiente,
conexión o de sentencia) pasado comoun argumento de
entrada.
SQL-STILL-EXECUTING
2
Una
función
que
fué
iniciada
forma
enasíncrona
continua
ejecutándose.
SQL-NEED-DATA
99
Mientras
procesaba
se
una sentencia, el driver
determinó
que
la aplicación necesita enviar datos de parámetros.
función
SQLErrorO
Usar
falló.
Laobtener
para
e información del error.
no existe
el SQLSTATE
La aplicaci6n es responsable de tomar las acciones apropiadas basadas en el cbdigo de retorno
que se genera.
Los tipos de datos
Las siguientesdeclaracionesde definicidnde tipomuestran los tiposdedatosusadosenlos
ejemplos de c6digo enC mostrados en dsta obra.Su equivalencia con los tipos de Visual Basicse
indican en el comentario que sigue ala declaracidn.
char f
t
ypede
int
typede long
f
short int
t
ypedef
typedef double
t ypedef float
t ypedef void *
typedef PTR
typedef long
SQLCHAR;
SQLINTEGER;
SQLSMALLINT;
SQLDOUBLE;
SQLREAL;
PTR;
SQLPOINTER;
HENV;
/ * equivale a Stringen VB * /
/ * equivale a Long en VB
*/
/ * equivale a Integeren VB * /
/ * equivale a Doubleen VB * /
/ * equivale a Singleen VB * /
/ * sin equivalencia en VB * /
/ * sin equivalencia en VB * /
/ * equivale a Long en VB * /
t y p e d e fl o n g
t y p e d e fl o n g
t y p e d e fl o n g
t y p e d e f HENV
t y p e d e f HDBC
t y p e d e f HSTMT
t y p e d e f HDESC
t y p e d e f SQLINTEGER
t y p e d e f RETCODE
HDBC ;
HSTMT;
HDESC;
SQLHENV;
SQLHDBC;
SQLHSTMT;
SQLHDESC;
RETCODE;
SQLRETURN;
/ * e q u i v a l e a Long en VB * /
/ * e q u i v a l e a Long en VB * /
/*
e q u i v a l e a Longen
/*
/*
/*
/*
equivale
equivale
equivale
equivale
equivale
VB
*/
a Long e n VB
a Long en VB
a Longen VB
a I n t e g e r en
a I n t e g e re n
*/
*/
*/
/ * e q u i v a l e a Long e n VB * /
/*
VB
VB
*/
*/
Estas definiciones tambikn se aplican en los tipos de datos referidos dentro de las sintaxis de las
funciones de ODBC que se exponen en esta parte. Se puede observar que
la mayoría de ellos
equivalen a tipos de datos simples
en Visual Basic, excepto porel tipo de dato apuntador el cual no
tieneequivalenciaenVisualBasic.
MAS adelantesever&unaformaindirecta
de manejode
apuntadores en Visual Basic cuando se analice
la funci6n SQLBindCol.
4
El manejo de instrucciones de SQL
En el capítulo anterior se estudiaron en detalle las funciones dela API para hacer la conexión con
una fuente de datos, cómo es que se deben de llamar Bstas, es decir,
el orden de llamada; sus
características mas sobresalientes, como sonlos códigos de retorno que cada una puede regresar,
e incluso se discutió sobre el manejo de errores. En este capítulo ahondaremos en la parte que
quedópendiente: la recuperacióndeinformacidn y el manejodelamisma.Tambiensetratará
sobre el acceso a la base de datos tanto para la lectura, como parala escritura o actualización de
los datos en ella.
4.1 Lo primordial: El handle de sentencia
Antes de que podamos realizar cualquier instrucción de lectura o escritura hacia la base de datos
necesitamos reservar recursos para tales operaciones. AI igual que como ocurrió parael ambiente
y la conexión, se necesita un handle mas, y este sera para la sentencia (recuerdese que laAPI de
ODBC esta desarrollada enC, el cual es el lenguaje de los apuntadores). La formade obtener &te
último handleen Visual Basic es como sigue, con la función SQLAllocStmt:
Dim rc
As Integer, hstmt As Long
rc = SQLAllocStmt(hdbc, hstmt)
SilafunciónregresaSQL-SUCCESS,setieneunhandledesentenciaasociadoalabasede
datos dada por el handle de conexión hdbc, el handle de sentencia obtenido puede usarse para
hacer todas las operaciones de SQL que se deseen, al terminar de usarlo se debe liberar con la
función SQLFreeStmt por limpieza, aunque se libera autometicamente con SQLDisconnect. Debe
tenerseencuentaqueesposibletenermasde
un handle de sentenciaasociadosaunode
conexidn.
33
34
La función SQLAllocStmt ()
Propósito
SQLAllocStmt() obtiene un nuevo handle de sentenciay lo asocia con la conexibn especificada por
el handle de conexibn que se pasa como argumento. No existe un número definido de handles de
sentencia que pueden ser creados para una misma conexibn.
Se debe llamar a SQLConnectO antes queMa a funcibn.
EstafunciónsedebedellamarantesquealasfuncionesSQLBindParamO,SQLPrepareO,
SQLExecuteO, SQLExecDirectO, o que cualquier otra funcibn que tenga un handle de sentencia
como uno de sus argumentos de entrada.
Sintaxis
SQLRETURN SQLAllocStmt (SQLHDBC hdbc, SQLHSTMT *phstmt);
Argumentos dela función
Tabla I O . Argumentos de SQLAllocStmt.
~~
Tipo de dato
Argumento
Entrada
SQLHDBC
SQLHSTMT
Salida*
hdbc
phstmt
Uso
Descripción
Handle de conexión
Apuntador al handle de sentencia
Comentarios
ElODBCCLIusacadahandledesentenciapararelacionartodos
los descriptores,resultados,
información del cursor e informacibn de estado para la instruccibn SQL procesada. Aunque cada
instruccibndeSQLdebetenerunhandledesentencia,sepuedenreusar
los handlespara
diferentes instrucciones.
Para ejecutar una actualizacibn o borrado por posicibn, la aplicacibn debe usar diferentes handles
de sentencia parala instruccibn SELECT y para las instrucciones UPDATEo DELETE.
Si el apuntador al handle de sentencia (phstmt) apunta a un handle de sentencia valido obtenido
por una llamada previa a SQLAllocStmt(),el valor original del mismo es sobrescrito como resultado
de la llamada a esta funcibn.
Códigos de retorno
SQL-SUCCESS
0
SQL-ERROR
0
SQL-INVALID-HANDLE
Si se regresa SQL-ERROR, el argumento phsfmf es puesto a SQL-NULL-HSTMT. La aplicacibn
debe
de
llamar
a
SQLErrorO
con
el mismo hdbc y con el argumento hstmt puesto
a
SQL-NULL-HSTMT.
35
4.2 SQLExecDirect: Ejecutar instrucciones de SQL
Despues de obtener el handle de sentencia, ya podemos mandar nuestros comandosy consultas
al DBMS de nuestrabase de datos. Los tipos de instrucciones de SQL que podemos usar son
muy
variados,algunas de lascualespuedenregresar
o no conjuntos de resultados,setienenpor
ejemplo:
instrucciones de consulta: SELECT. Regresa un conjunto de resultados.
instruccionesdemodificacióndedatos:INSERT,UPDATE,DELETE.Noregresanun
conjunto de resultados.
instrucciones de modificaciónde la basededatos:CREATETABLE,
regresan un conjunto de resultados.
DROPTABLE.
No
instrucciones de comandos: EXECUTE. Si ejecuta un Stored Procedure que regresa valores
entonces tambiBn regresa un conjunto de resultados.
y otras específicas del DBMS que se este utilizando.
pero toda instrucci6n se construye y procesa en forma de cadena de caracteres o String. Para
hacer esto utilizamos la funciónSQLExecDirect de la API de ODBC, que en un programa de Visual
Basic quedaríacomo sigue:
Dim rc As Integer, query As String
query = "SELECT * FROM TABLA"
rc = SQLExecDirect (hstmt, query,
Len
(query)
)
para procesar una instrucción, Bsta se pasa como un argumento de cadena, tambiBn se necesita
pasar la longitud en bytes dela cadena; si el código fuera en C, bastaría utilizar parala longitud de
la cadena la macro SQL-NTS, para indicar que la cadena de caracteres es una cadena terminada
con el carhcter terminador nulo. Unavez hecha la consulta se utilizael mismo handle de sentencia
paraobtener los resultadosde Bsta, si esquelainstruccibnpasadacomoargumentoregresa
resultados.
La función SQLExecDirect ()
Propósito
SQLExecDirect ejecuta en forma directa la instrucción de SQL especificada. Las sentencias sólo
pueden ser ejecutadas una a la vez. AdemBs, el servidor de la base de datos conectada debeser
capaz de prepararla sentencia.
Sintaxis
SQLRETURN SQLExecDirect (SQLHSTMT
SQLCHAR
SQLINTEGER
hs tmt ,
*szSqlStr,
cbSqlStr);
36
Argumentos de la funci6n
Tabla 11. Argumentos de SQLExecDirect.
Tiipo de dato
Argumento
Uso
SQLHSTMT
hstmt
Entrada
Handle
sentencia.
de
Descripción
No debe existir ningun
cursor
abierto
asociado con hstmt, verSQLFreeStmt para más
información.
SQLCHAR
szSqlStr
Entrada
Cadena
de
la sentencia
de
SQL.
El servidor de base
de
datos conectado debe ser capaz de preparar
la sentencia.
SQLINTEGER
cbSqlStr
Longitud del contenido del argumento
szSqlStr.
La
longitud
debe ser ya seala longitud exacta de la cadena de
sentencia, o si la cadena de sentencia está terminada en
nulo, utilizar SQL-NTS.
Entrada
Comentarios
La sentencia SQL no puede ser COMMIT
o ROLLBACK, paraello se usa la funcidn SQLTransactO.
ParamásinformacidnsobrelassentenciasSQLsoportadasreferirsea
la documentacidndel
controlador de ODBC utilizado.
LacadenadelainstruccidnSQLpuedecontenermarcadoresdeparámetros.Unmarcadorde
"?", eindicaunaposicidnenlasentenciadondese
parámetroserepresentaporuncaracter
sustituirá el valordeunavariabledelaaplicacibn,cuandoSQLExecDirectOesllamado.
SQLBindParamO liga (o asocia) una variable de la aplicacidn a cada marcador de parametro, para
indicar si cualquierconversidndedatossedeberealizar
al tiempoenque
los datosson
transferidos. Todos los parametros deben estar ligados antes de llamar a SQLExecDirectO.
Si la sentencia es un SELECT, SQLExecDirectO genera un nombre de cursor, y enseguida abre el
cursor. Si la aplicacidn ha usado SQLSetCursorName() para asociar un cursor con
el handle de
sentencia, El CLI asocia el nombre de cursor generado por la aplicacidn con el cursor generado
internamente.
Pararecuperaruna
línea dedatos del conjuntoderesultadosgeneradoporunasentencia
SELECT, se utiliza SQLFetchO despues de que SQLExecDirectO se ejecutd con 6xito.
Si la sentencia SQL es un DELETE por posicibno un UPDATE por posicidn,el cursor referenciado
en la sentencia debe estar posicionado en unalínea de datos. Adicionalmente la sentencia de SQL
debe definirse en un handle de sentencia separado bajo
el mismo handle de conexidn.
No debe haber un cursor abierto asociado con
el handle de sentencia.
Códigos de retorno
SQL-SUCCESS
SQL-SUCCESS-WITH-INFO
SQL-ERROR
SQL-INVALID-HANDLE
SQL-NO-DATA-FOUND
SeregresaSQL-NO-DATA-FOUND
si lasentenciaSQLesunUPDATEdebúsqueda
DELETE de búsqueda yno hay líneas que satisfagan la condicidn de búsqueda.
o un
37
4.3 SQLBindCol: Asociando variablesy columnas
Lafunción SQLBindCol permite ligar variables con las columnas de un conjunto de resultados,
facilita la conversidn de tipos de datos
y permite una programacidn rnhs sencilla que la que
se
tendría utilizando únicamente la funcibn
SQLGefDafa, pararecuperarcolumnasindividuales.La
funcidn asocia una direccibn de memoria con una columna de datos y las subsecuentes llamadas a
SQLfetch colocan los datosdelacolumna
y renglbndentrodelalocalidaddememoria
especificada.
Sin embargo, su utilizacidnen Visual Basic no es tan trivial, ya que por ser este un lenguaje de alto
nivel, presenta algunas deficiencias en cuanto a las facilidades que otorga al programador para el
manejo de memoria frente a otros lenguajes de nivel medio, como
C por ejemplo; aun mas, en
Visual Basic no existeel concepto de apuntador-tan común en C - q u e es esencial para el usode
algunas funciones de ODBC que devuelven o requieren direcciones de memoria. El problema de
los apuntadores puede sortearse usando algunas de las funciones de la Windows API; con 6stas
se pueden reservar espacios de la memoriay obtener los apuntadores a estos dentro de variables
de tipo Long como se ver$ mas adelante en este apartado.
Despuésdeenviarunaconsultade
SQL,unaaplicacidndeODBCliga
los resultadosdeesa
consulta con variables. Comúnmente se asocia una variable con cada columna del conjunto de
resultados. La siguiente es la declaracibn de SQLBindCol que debe usarse en un programa Visual
Basic:
Declare Function SQLBindCol Lib "Odbc32 .dll"
( ByVal
hstmt
As
Long, ByVal
icol
As
Integer,
ByValfCTypeAsInteger,
rgbValue
As
-Y, ByVal cbValueMaxAs Long, pcbValue
As Long As Integer
Esencialmente se pasa un apuntador a SQLBindCol en el argumento rgbValue. Despues el driver
el apuntadorencada
deODBC coloca los datos en la localidad de memoria especificada por
ejecucidn de SQLfetch. Posteriormente la aplicacidn puede recuperar los datos referenciando a
esa localidad de memoria.
El manejo de variables de Visual Basicy SQLBindCol
A diferencia de los otros tipos de datos, las variables de tipo String son movidas constantemente
en la memoria por Visual Basic, esto con el fin de queel contenido de 6stas no est6 particionadoy
se encuentre completo dentro de una misma phgina de memoria, así como para eficientar
el uso
deesta.Debidoaellono
es recomendableusarvariablesdetipo
String directamenteconla
funcidn SQLBindCol, puesaunquesepaseladireccidndelavariabledecadenamediantela
palabra reservada ByVal, como se muestra a continuacibn:
Dim sCadena AsString, rc As Integer, lCadena As Long
sCadena = SpaceS(255,O) 'Reserva espacio en la cadena
rc = SQLBindCol(hstmt, 1, SQL-C-CHAR, ByVal sCadena, 254, 1Cadena)
no existe garantia de que la cadena permanecer$en la misma direccidn de memoria antes de que
se llame a la funcibn SQLFetch. Usar cadenas de VB con SQLBindCol puede resultar no s610 en
datos incorrectos sino también en Fallos de Proteccidn General.
38
Sin embargo, si es posible utilizar con seguridad los tipos numericos como Long o Integer, pues
&tos ocupan localidades fijas de memoria y Visual Basic las respeta. El cbdigo siguiente correra
sin problemas:
Dim Numero As Long, rc As Integer
rc = SQLBindCol(hstmt, 1 , SQL-C-LONG,
Numero, O , O )
Nbtesequenoesnecesarioespecificar
el tamanodelbufferconcbValueMax
ni recuperarla
longituddeldatoenpcbValue,comoseríapara
un datodetipo SQL-C-CHAR. Tampocofue
necesario usar la palabra reservada ByVal, pues a diferencia de las cadenas, utilizarla implicaría
pasar el contenido de la variablenumkrica y no su direccibn en memoria,lo cual sería incorrecto.
Es posible pasar la direccibn de una cadena de
VB a SQLBindCol pero como las cadenas son
movidas en la memoria por VB, noes seguro usar SQLBindCol sin primero bloquearla memoria. A
continuacibn se discute el uso de cadenas de VB con SQLBindCol y las llamadas a las funciones
de la API de Windows GlobalAlloc, GlobalLock, lstrcpyn, GlobalUnlock y GlobalFree para reservar,
bloquear y copiar datos dela memoria a cadenas de Visual Basic.
Usando cadenas deVisual Basic con SQLBindCol
En Visual Basic, para pasar un apuntador de cadena a una DLL, se utiliza
la palabra reservada
ByVal precediendo ala variable de cadena. Cuando se utiliza la palabra
ByVal se le dice tambikn a
Visual Basic que pasara una cadena terminadaen nulo, o sea, una cadena cuyo último caracter es
un "carácter nulo" (cero binario).
Es raramente posible (y muy arriesgado) usar cadenasde VB con SQLBindCol, siempre y cuando
no se manipulen otras cadenas (incluyendoel texto de los controles) duranteel lapso de tiempoen
que las cadenas est& ligadas. Durante
el procesamiento normal, como ya vimos, VB reorganiza
peribdicamente su espacio de cadenas. Esto implica que las cadenas se moveran en memoria y
sus direccionesnoseranlasmismas.Comoresultadodeesto,lasdireccionespasadasa
SQLBindCol yanotendranvalidez.Pero,siaúndelodichoanteriormente,setieneundeseo
desmedido de usar cadenas deVB con SQLBindCol se pueden seguir las siguientes reglas:
No manipularotrascadenasentrelasllamadasaSQLBindCol
y SQLFreeStmtcon
SQL-UNBIND. Un ejemplo común es que durante un ciclo de SQLFetch se concatenen las
variables ligadasen una sola cadenay despues anadir 6sta a una caja
de texto.
Cuando se liguen cadenas, ligar cadenas delongitud variable, y no cadenas de longitud fija.
Las cadenas de longitud variable
se declaran así:
Dim mysfr as String
No ligar arreglos de cadenas. Los arreglos de cadenas se almacenan en segmentos64K
de
y Visual Basic podría mover los elementos del arreglo para recobrar espacio de cadena
fragmentado.Comoresultado de esto, el elementodelarreglo al queunacolumnaeste
ligado podria volverseinvididoenunsiguienteSQLFetch.ComoSQLExtendedFetch
requiere específicamente ligas con arreglos, se recomienda no usar SQLExtendedFetch en
Visual Basic.
Antesdeligarlascadenasdelongitudvariable,sedebeninicializarcomosigue,para
reservar espacio de memoria para
la cadena.
mysfr = Sfring$(255, O)
39
Cuando se llame a SQLBindCol y se ligue a una cadena (si rgbValue sera una cadena), usar
la palabraByval. Por ejemplo,
SQLBindCol(hsfmt&, 7, SQL-C-CHAR, Byval mystr, cbMax&, cbVal&)
Usando memoria global: funciones de la WinAPl
Es posibleusar las funciones de la APIdeWindows:GlobalAlloc,GlobalLockylstrcpynpara
obtener una porcidn dememoria fija, ligar las columnas con SQLBindCol a 6sta memoria, y copiar
los datos desdela memoria hasta cadenas de Visual Basic.
GlobalAlloc:
Reserva un bloque de memoria y regresaun handle a la memoria
si la funcibntiene 6xito. Se debe reservaruna porcidn de memoria
por cada columna que se desee ligar.
GlobalLock:
Bloquea la memoria reservada con GlobalAlloc y regresa un
apuntador ala memoria. Se debe usarGlobalLock para obtener
un apuntador el cual usar con SQLBindCol.
Istrcpyn:
Copia el contenidode la memoriadesde una direcci6naotraun
número específico de bytes.
Se debe usarlstrcpyn para copiarel
contenido de la memoria a la cadena
de longitud variable.
Nota: Cuando se termine de usar la memoria
se deben llamar a las funciones
Globalfree para liberarla memoria yel selector usado porGlobalAlloc.
GlobalUnlock y
Se deben añadir las siguientes declaraciones (Listado 5) en la seccibn (general) (declarations) de
algún m6dulo de cddigode la aplicaci6n Visual Basic:
Listado 5. Declaraciones necesariaspara usar las funcionesde memoria de la Win A P L
'Constantes para GlobalAlloc
Public Const GMEM-FIXED= &HO
Public Const GMEM-INVALID-HANDLE= &H8000
Public Const GMEM-MOVEABLE= &H2
'Declaraciones de las funcionesde memoria
Declare Function lstrcpynLib "kerne132" Alias "IstrcpynA"( ByVal lpStringl AsAny, ByVal lpString2 As Any, ByVal iMaxLength As -Long
) As Long
Declare Function GlobalAlloc Lib "kerne132"
( ByVal wFlags As Long, ByVal dwBytes As Long
) As Long
Declare Function GlobalLock Lib "kerne132" (ByVal hMem As Long) As Long
Declare Function GlobalUnlock Lib "kerne132" (ByVal
hMem As Long) As Long
Declare Function GlobalFree Lib "kerne132" (ByVal hMem As Long) As Long
El Listado 6 ilustra el uso de las funciones de la WinAPl junto con la funcibn SQLBindCol para
obtener datos de tipoSQL-C-CHAR, el manejo de errores se omite por simplicidad:
40
Listado 6. Uso de la función SQLBindCol con variables de cadena.
Private Sub Fom-Click0
-"1
""
'Para la conexión
1"""""""""""""""""""""""-
Dim henv As Long 'Handle
de ambiente
Dim hdbc As Long 'Handle de conexión
I"""""""""""""""""""""""-
'Para la sentencia
1"""""""""""""""""""""""-
Dim hstmt As Long 'Handle de sentencia
Dim rc As Integer 'Código de retorno
Dim sql As String 'Sentencia SQL
1"""""""""""""""""""""""-
'Para SQLBindCol
1"""""""""""""""""""""""-
'Cadena para contener el
dato de la columna
Dim sCadena As String
'Longitud deldato regresado en la columna
Dim 1CadenaLenAs Long
'Apuntador a la memoria para ligar la columna
Dim 1pAddrCadena As Long
'Handle de memoria
Dim hMemCadena As Long
'Longitud máxima del buffer de almacenamiento
Dim cbValueMax As Long
'Obtenemos el handlede ambiente
rc = SQLAllocEnv (henv)
'Obtenemos el handle de conexión
rc = SQLAllocConnect(henv, hdbc)
'Efectuamos la conexión
rc = SQLConnect (hdbc, "BaseDatos", 9, "Usr", 3, "Pass", 4 )
'Obtenemos un handle de instrucción
rc = SQLAllocStmt(hdbc, hstmt)
'Ejecutamos directamente la instrucción
sql = "SELECT Columna FROM
Tabla"
rc = SQLExecDirect (hstmt,
sql, Len(sq1)
1"""""""""""""""""""""""-
'Preparamos todo para SQLBindCol
1"""""""""""""""""""""""-
cbValueMax
=
254
I
'Inicializamos el espacio en la cadena
I
sCadena
=
String$
(255,
O)
1
'Reservamos
memoriay obtenemos
un
apuntador
a
ésta
1
hMemCadena = GlobalAlloc(GMEM-MOVEABLE, Len(sCadena))
1pAddrCadena = GlobalLock(hMemCadena)
Debug.Print 1pAddrCadena
'Ligamos la columnacon el apuntador. Porser de tipo Long, la
'variable 1pAddrCadena se pasa por valor para quesu pase
contenido,
'el cual es el apuntador
al espacio de memoria reservado.
41
rc
=
SQLBindCol(hstmt, 1, SQL-C-CHAR, ByVal IpAddrCadena, cbValueMax,1CadenaLen)
I
'Hacemos el Fetch
1
rc
=
SQLFetch(hstmt)
1
'Copiamos la cadena de la memoria a una cadena de VB,se toma
'en cuenta el caracter terminador nulo por
lo que se añade 1
1
Call lstrcpyn(ByVa1 sCadena, ByVal IpAddrCadena, 1CadenaLen
+ 1)
Debug.Print sCadena
1
'Desligamos columnasy liberamos memoria
I
rc
rc
rc
=
=
=
SQLFreeStmt (hstmt,
SQL-UNBIND)
GlobalUnlock(hMemCadena)
GlobalFree(hMemCadena)
1
'Desconectamos y liberamos handles
I
rc
rc
rc
rc
=
=
=
=
SQLFreeStmt(hstmt, SQL-DROP)
SQLDisconnect (hdbc)
SQLFreeConnect(hdbc)
SQLFreeEnv (henv)
End
End Sub
El cbdigo anterior es un ejemplo muy sencillo para ligar solamente una columna conuna variable.
Para ligar más columnas se debe reservar memoria y obtener un apuntador a la misma con las
funciones GlobalAlloc y GlobalLock por cada columna que se desee ligar, como se hizo
en el
ejemplo. Se pudo haber usado la funcidn
lstrcpy enlugarde lstrcpyn, la funcibn lstrcpy puede
copiar cadenas terminadas en carácter nulo a variables de cadena de
VB sin necesidad de indicar
la cantidad de los bytes a transferir. Pero siendo estrictos, la funcidn lstrcpyn es la más adecuada
para el caso.
La función SQLBindCol ()
Propósito
SQLBindCol()asocia(liga)columnasdeunconjuntoderesultadosavariablesdeaplicacidn
(búffers de almacenamiento), para todoslos tipos de datos. La informacidn es transferida desdeel
DBMS hasta la aplicacibn cuando la funcibn SQLFetch() es llamada.
Esta funcibn también se usa para especificar cualquier conversibn
de datos que se requiera. Se le
llama una vez por cada columnadel conjunto de resultados quela aplicacidn necesite recuperar.
Las funciones SQLPrepareO o SQLExecDirectO se llaman usualmente antes que a esta funcibn.
También puede ser necesario llamar a las funciones SQLDescribeCol()
o SQLColAttributes().
SQLBindCol() debe ser llamada antes que a SQLFetchO, que transfiere los datos a los búffers de
almacenamiento especificados con ésta funcibn.
42
Sintaxis
hs tmt,
icol,
fCType,
rgbValue ,
cbValueMax,
*pcbValue);
SQLRETURNSQLBindCol(SQLHSTMT
SQLSMALLINT
SQLSMALLINT
SQLPOINTER
SQLINTEGER
SQLINTEGER
Argumentos de la función
Tabla 12. Argumentos de SQLBindCol.
__
Tipo
dato
deArgumento
hstmtSQLHSTMT
SQLSMALLINT
icol
SQLSMALLINT
fCType
uso
Descripción
Entrada
Handle de sentencia
Entrada
Número identificandola columna que se desea ligar. Las
columnas se numeran secuencialmente, de izquierda a
derecha, iniciando en 1.
Entrada
Tipo de dato enla aplicación parala columna con
número icol enel conjunto de resultados. Se soportan
los siguientes tipos:
o
O
O
O
o
O
O
o
Salida
(diferida)
SQLPOINTER
rgbValue
SQL-CHAR
SQL-VARCHAR
SQL-NUMERIC
SQL-DECIMAL
SQL-INTEGER
SQL-SMALLINT
SQL-FLOAT
SQL-REAL
SQL-DOUBLE
SQL-GRAPHIC
SQLVARGRAPHIC
SQL-DATETIME
SQLTYPE-DATE
SQL-TYPE-TIME
SQLTYPEJIMESTAMP
Especificando SQL-DEFAULT causa queel dato sea
transferido en su tipo de dato normal.
Apuntador al buffer dondeel CLI almacenaráel dato
cuando se llame aSQLFefcb.
Si rgbValue es nulo, la columna está desligada.
Entrada
SQLINTEGER
cbValueMax
SQLINTEGER *
pcbValue
Salida
(diferida)
Tamaño del buffer rgbValue en bytes disponible para
almacenar los datos de la columna.
Si fCType es ya sea SQL-CHAR o SQL-DEFAULT,
entonces cbValueMax debe ser> O o de lo contrario la
función regresa un error.
Apuntador al valor que indicael número de bytes de
información almacenados enel buffer rgbvalue.
SQLFetch() regresaSQL-NULL-DATA en éste
argumento si el dato de la columna es nulo.
43
Nota: Para 6sta funcidn, tanto rgbValue como cbValue son salidas diferidas, lo que significa que
las localidades de almacenamiento a las que esos apuntadores apuntan
no son actualizadas hasta
queSQLFetch()esllamada.Laslocalidadesreferenciadasporesosapuntadorespermanecen
validas hastaque se llama aSQLFetchO.
Comentarios
Una aplicación llama a SQLBindCol()una vez por cada columna del conjunto de resultados que se
quiera recuperar. Cuando se llama a SQLFetchO, la informaci6n en cada una de esas columnas
ligadas es colocado enel lugar asignado (dado por
los apuntadores rgbValue y cbValue).
La aplicacidnpuedeconsultarprimero
los atributosdelacolumna(talescomotipodedato
y
longitud) llamando a SQLDescribeCol() o a SQLColAttributes(). Esta informaci6n puede entonces
ser usada para especificar el tipo de dato correcto de lasAreas de almacenamiento, o para indicar
conversiones de datos aotros tipos.
En extraccionesde datos posteriores, la aplicación puede cambiarlas asociaciones alas columnas
o ligar otras columnas llamando a SQLBindCol(). Las nuevas ligas
no aplican a datosya extraídos,
sino que son usadas en la siguiente llamada a SQLFetch(). Para desligar una columna, se llama a
SQLBindCol()con el valorde rgbValue puestoaNULL.Paradesligartodaslascolumnas,
la
foption puestoa
aplicaciónpuedellamaraSQLFreeStmtOcon
el argumentodeentrada
SQL-UNBIND. No es posible desligar columnas individuales con
SQLFreeStmt.
Las columnas se identifican con un número, asignado secuencialmente de izquierda a derecha,
comenzando con 1. El número decolumnasen el conjuntoderesultadospuededeterminarse
llamando a las funciones SQLNumResultCols() o SQLColAttributes(), esta última conel argumento
fdescType puesto a SQL-DESC-COUNT.
Una aplicación puede escoger no ligar todas las columnas, o aún no ligar ninguna columna. Los
datos en las columnas no ligadas (y solamente de las columnas no ligadas) pueden recuperarse
usandoSQLGetDataOdespuesdellamaraSQLFetch().SQLBindCol()esmaseficienteque
SQLGetDataO, y debe ser usado siempre que sea posible.
La aplicación debe asegurarse de que se ha reservado el suficiente espacio de almacenamiento
para la informaci6n a ser recuperada. Si el buffer es para contener datos de longitud variable, la
aplicacióndebereservartantoespaciodealmacenamientocomolamaximalongitudque
la
columna ligada requiera, de lo contrario el dato puede truncarse. Si ocurre el truncamiento de un
dato de cadena, se regresa SQL-SUCCESS-WITH-INFO
y el valor de pcbValue es puesto a la
longitud actual restantede rgbValue para enviar hacia la aplicacibn.
Códigos de retorno
SQL-SUCCESS
SQL-ERROR
SQL-INVALID-HANDLE
44
4.4 SQLFetch: Navegar por los resultados
Despues de que se ha ejecutado una sentencia SQL de consultao un SELECT, podemos usar el
mismo handle de sentencia pasado a la funcidn SQLExecDirect para navegar por el conjunto de
resultados y posicionarnos sobre la línea deseada para despues obtener los datos con la función
SQLGetData o desde las variables ligadas con SQLBindCol. Para cumplir con esta misión tenemos
a la funcidn SQLFetch. La funcidn SQLFefch mueve el cursor asociado con un handlede sentencia
una línea hacia delanteen el conjunto de resultados,la forma en que se haría esto en Visual Basic
es la siguiente:
Dim rc As Integer
rc = SQLFetch(hstmt)
SQLFetch regresa SQL-SUCCESS cuando se ha posicionadocon &xitoen la siguiente línea de los
datos. Cuando el cursor esta en el último rengldn de datos y se llama a SQLFetch, esta regresa
SQL-NO-DATA-FOUND, indicando quese ha llegado al final del conjunto de resultados.
Para recorrer todoel conjunto de informacidn se debe utilizar SQLFetch dentro un
deciclo iterativo,
por ejemplo un ciclo while sería muy conveniente, ya que prueba primero la condicidn antes de
lo queesadecuadocuandoesposiblequela
ejecutarlasinstruccionesdesubloqueinterno,
consulta arroje un conjunto vacío de resultados. La forma en que
se haría esto es como sigue:
Dim rc
As Integer
SQLFetch(hstmt)
While KC <> SQL-NO-DATA-FOUND
'Obtener l o s datos con SQLGetData
'Poner el cursor en la siguiente línea
rc = SQLFetch(hstmt)
Wend
KC =
Obskrvese que en el caso de que la consulta asociada conhstmf sea un conjunto vacío, es decir,
que la consulta no arroje resultados, el valor del cddigo de retorno de SQLFetch sera en forma
inmediata SQL-NO-DATA-FOUND, así pues al evaluar la condicidn delciclo while esta sera falsa,
por lo quela parte interna del mismo sera pasada por alto.
La función SQLFetch ()
Propósito
SQLFetchO posiciona el cursor en la siguiente linea del conjunto de resultados, y recupera las
columnasqueesténinvolucradasen
la consulta.SepuedeusarSQLFetchOpararecibirdatos
directamente en las variables que sean especificadas con SQLBindCol(), o se pueden recuperar
lascolumnas enformaindividual
despub del fetch,llamandoa
SQLGetDataO.Lafuncidn
SQLFetchO tambien realiza la conversidn de datos,si se indicd esta cuando la columna fue ligada
con SQLBindCol.
Sintaxis
SQLRETURN
SQLFetch
(SQLHSTMT
hstmt)
;
45
Argumentos de la función
Tabla 13. Argumentos de SQLFetch.
Tipo de dato
Argumento
Uso
Descripción
SQLHSTMT
sentenciade Handle
Entrada
hstrnt
Comentarios
SQLFetchO s610 puedeserllamadosilamasrecientesentenciaejecutada
SELECT.
El número de variables de aplicacibn ligadas con SQLBindCol() no debe exceder
columnas enel conjunto de resultados o SQLFetchO fallara.
en hstmt, fue un
al número de
Si SQLBindCol() no ha sido llamado para ligar columnas, entonces
SQLFetchO no regresa datos a
la aplicación, y únicamente avanza el cursor. En 6ste caso se puede llamar a SQLGetDataO para
obtenertodas las columnasenformaindividual.Losdatosdelascolumnassondescartados
cuando SQLFetchO avanzael cursor a la siguiente línea.
Si algunavariableligadaacolumnano
esdelacapacidadadecuadaparacontener
el dato
regresadopor SQLFetchO, el datoestruncado.Si
los datosquesontruncados
son datosde
carácter, la funcibn regresa SQL-SUCCESS-WITH-INFO, y se genera un SQLSTATE que indica
el truncamiento. El argumento de salida de SQLBindCol() pcbValue, contiene la longitud del dato
recuperado de la columna. La aplicacibn puede comparar la longitud de la salida con la longitud de
la entrada (argumentos @Value y cbValueMax en SQLBindCol()) para determinar que columnas
de caracteres han sido truncadas.
El truncamiento de los tipos num6ricos no está senalado si el truncamiento implica dígitos a la
derecha del punto decimal. Si el truncamiento ocurre ala izquierda del punto decimal, se devuelve
un error y el SQLSTATE de truncamiento de dato.
El truncamiento de tipos de datos grdficos se trata igual que con los tipos de datos de caracter.
Excepto que el búffer rgbValue se llene al múltiplo m& cercano a dos bytes y que permanezca
menor o igual queel valor de cbValueMax especificado en SQLBindCol().
Cuando todas las líneas han sido extraídas del conjunto de resultados, o las líneas restantes no
sean necesarias, se debe llamar a SQLFreeStmtO para cerrarel cursor y desechar la informacibn
remanente de la consulta los
y recursos asociados a la misma.
Códigos de retorno
SOL-SUCCESS
SQL-SUCCESS-WITH-INFO
SQL-ERROR
SQL-INVALID-HANDLE
SQL-NO-DATA-FOUND
La funcibn devuelve SQL-NO-DATA-FOUND si no existen renglones de datos en el conjunto de
resultados, o las llamadas anteriores a SQLFetchO han abarcado todas las lineas del conjunto de
resultados.
46
4.5 SQLGetData: Recuperando la información por
columnas
Cuando el cursor ya se encuentra ubicado enla línea de datos que nos interesa podemos iniciar la
extracción de los datos de cada una de las columnas. Tocael turno a la funci6n SQLGetData, bsta
funci6n extrae la informaci6n de la columna que se le indique y la convierte al tipo de dato que
tambibn se le pasa como argumento. Se debe llamar a la funci6n SQLGefData por cada columna
que se desee recuperar, para lo cual es muy útil la funci6n SQLNumResultCols, la cual determina
elnúmerodecolumnasconlasquecuentaelconjuntoderesultados.
El usodebstasdos
funciones se ejemplificaen el Listado 7, el manejo de errores se omite por sencillez.
Listado 7. Uso de las funciones SQLGetData y SQLNumResultCols.
Const 1ongBuffer As Long = 255
Dim rc As Integer
Dim IAs Integer
Dim cadFija As String
* 1ongBuffer
Dim longDato As Long
Dim NumCols As Long
Dim Datos( ) As String
'Ejecutar la consulta
rc = SQLExecDirect(hstmt, "Select * From Tabla", 19)
'Obtiene elnúmero de columnas
rc = SQLNumResultCols (hstmt, NumCols)
'Ir al primer renglónde datos
rc = SQLFetch(hstmt)
'Obtiene l o s datos de todas las columnas
ReDim Datos(1 To NumCols) As String
For I = 1 To NumCols
cadFija = String$ (longBuffer,
O)
longDato = O
rc = SQLGetData(hstmt, I, SQL-C-CHAR, cadFija, longBuffer, longDato)
If longDato < 1 Then
Datos (I) = '"' 'Columna con dato nulo
Else
Datos (I) = Left$ (cadFija, longDato)
End If
Next I
En el ejemplo anterior cabe resaltar el uso de una cadena fija como argumento de salida de la
funci6n SQLGefData. La raz6n de esto es que la funci6n requiere de un buffer de longitud fija para
colocar la informacibn, la longitud maxima del buffer esta dada por
el argumento longSufer. El otro
en
argumento de salida,longDato, indica el número de bytes de informaci6n valida cadfija.
Como se vera en los siguientes parrafos, el argumento de salida cadFija es un apuntador al buffer
contenedor del dato en la versi6n C de
la función; tambibn el argumento representado porlongDato
es un apuntador a una variable de tipo long int, mas sin embargo, el truco consiste en declarar el
argumento como ByVal rgbValue As String en lugar de void * rgbValue como seria en la versi6n en
C de la funci6n. Lo anterior funciona con SQLGetData, pero no con SQLBindCol, la versi6n Visual
Basic de la funci6n SQLBindCol declara rgbValue como Any. La raz6n de esto estriba enel manejo
de Visual Basic delas variables de tipo cadenao String: Visual Basic reacomoda automaticamente
las variables de tipo cadena en la memoria, de forma
que el contenido de las variables permanezca
47
integro dentro de una misma paginade memoria, es por ello queaún si obtenemos el apuntador a
una variable de tipo cadena con LSTRCPY, al hacer VB el reordenamiento de las variables, la
variablepara la queobtuvimos el apuntadortendra unanuevadireccibndememoria.
AI usar
SQLGetData, la funcibnpasainmediatamente el datoen la columnaa la variabledecadena
representada por rgbvalue, y aunque esta sea reacomodada en la memoria por VB, la informacibn
queyacontienenoesalterada.Encambio,para
el caso de SQLBindCol, aunquepasemosla
direccibn de la variable de cadena con ByVal cadfija, éSta puede cambiar antes de efectuarse el
Fecth y la direccibn antes pasadaya no sera valida. Los resultadosson impredecibles.
La función SQLGetData ()
Propósito
SQLGetDataO recuperadatosdealgunadelascolumnasen
la Ihea actual del conjunto de
resultados. Esta funcibn es una alternativa a SQLBindCol(), lacual transfiere datos directamente a
variables de la aplicacidn en las llamadas aSQLFetchO. SQLGetDataO puede usarse también para
leer datosde carActer de gran tamano por fragmentos de éstos.
Se debe llamar a SQLFetch() antes que a SQLGetDataO.
Despues de llamar a SQLGetDataO para cada columna,
siguiente renglbnde datos.
Se llama a SQLFetchO para obtener el
Existe otra funcibn llamada SQLGetCol() identica a SQLGetDatao, ambas funciones se soportan
por compatibilidad.
Sintaxis
hstmt ,
icol,
fCType,
rgbvalue,
cbValueMax,
*pcbValue);
SQLRETURNSQLGetData(SQLHSTMT
SQLSMALLINT
SQLSMALLINT
SQLPOINTER
SQLINTEGER
SQLINTEGER
Argumentos de la función
Tabla 14. Argumentos de SQLGetData.
Uso
Argumento
dato
de
Tipo
Descripcidn
sentencia
de Handle
Entrada
SQLHSTMT
hstmt
SQLSMALLINT
icol
Entrada
Número
columna
la
de
cual
la
de
desea
serecoger
el
dato. La primer columna se indica con
el numero 1.
SQLSMALLINT
fCType
Entrada
Tipo
columna
dato
de
la
de identificada
por
icol.
Se
soportan los siguientes tipos:
O
O
O
SQL-CHAR
SQLVARCHAR
SQL-NUMERIC
SQL-DECIMAL
SQL-INTEGER
SQL-SMALLINT
SQL-FLOAT
48
Tipo de dato
Argumento
Uso
Descripci6n
O
O
O
O
SQL-REAL
SQL-DOUBLE
SQL-GRAPHIC
SQL-VARGRAPHIC
SQL-DATETIME
SQLTYPE-DATE
SQLTYPE-TIME
SQLTYPE-TIMESTAMP
SQLPOINTER
rgbValue
Salida
Apuntador
búffer
donde
al será
almacenado
dato
el
recuperado dela columna.
SQLINTEGER
cbValueMax
Entrada
Tamaño
máximo
búffer
delapuntado
rgbValue
por
SQLINTEGER *
pcbValue
Salida
Apuntador
al valor
que
indica
número
el bytes
de
disponibles en el bufferrgbvalue. Si el dato está
siendo recuperado en piezas, contieneel número de
bytes faltantespor recuperar, sin incluirlos bytes de
las columnas que han sido obtenidos en llamadas
previas a SQLGetDataO.
El valor esSQL-NULL-DATA si el valor del dato es
nulo. Si éste apuntador está como
NULL y SQLFetchO
ha obtenido una columna que contiene
un nulo, ésta
función fallará puesto que no tiene forma de reportar
ésto.
Si SQLFetchO ha extraido una columna que contiene
datos gráficos, el apuntador a pcbValueno debe ser
nulo o ésta función fallará porque no tendrá medios
para informarle a la aplicación sobre la longitud
del
dato recuperado en el buffer
rgbvalue.
Comentarios
SQLGetDataO puede ser usadajunto con SQLBindCol() para la misma línea, siempre queel valor
de icol no especifique una columna que haya sido ligada. Los pasos generales son:
1. SQLFetchO-avanza el cursor a la primer linea, extrae el primer renglón, transfiere los datos
de las columnas ligadas.
2. SQLGetDataO-transfiere los datos de columnas específicas (no ligadas).
3. Repetir el paso 2 para cada columna que sea necesaria.
4. SQLFetchO-avanza el cursor a la siguiente línea, extrae el siguiente renglón, transfiere los
datos de las columnas ligadas.
5. Repetir los pasos 2, 3 y 4 paracadarenglón del conjunto de resultados, o hasta que' el
conjunto de resultadosya no sea necesario.
SQLGetDataO recupera columnas voluminosas si el tipo de dato C (fCType) es SQL-CHAR o si
fCType es SQL-DEFAULT y el tipo de la columna esCHAR o VARCHAR.
EncadallamadaaSQLGetDataO,
si lalongituddeldatoaregresar
es mayor o iguala
cbValueMax,ocurreuntruncamiento.
El truncamiento se indica con el código de retorno de la
función de SQLSUCCESS-WITH-INFO aunado a
un SQLSTATE que denota truncamiento de
datos. La aplicacidn puede entonces llamar a SQLGetDataO nuevamente, con
el mismo valor de
icd, paraobtener el resto dela informacióndelamismacolumnainiciandoen
el puntode
49
truncamiento.Paraobtenerlacolumnaentera,
la aplicacidnrepitelasllamadashastaquela
funcidndevuelve el cddigo de retorno SQL-SUCCESS.La siguientellamadaa SQLGetDataO
regresara el cddigo de retornoSQL-NO-DATA-FOUND.
Paradescartarlaspartes
de datosrestantesporrecuperar,
la aplicacidnpuedellamara
SQLGetDataO con el valor de icol puestoalasiguienteposicidndecolumna
de interés.Para
descartar los datos no recuperados de una linea entera, la aplicaci6n debe llamar a SQLFetchO
para avanzar el cursor a la siguiente linea; o, si ya no hay interés en ningún dato mas del conjunto
de resultados, se llama a SQLFreeStmtO para cerrar
el cursor.
El argumento de entrada fCType determina el tipo de conversidn de datos (si existe) necesaria
antes de que el datoseacolocadoen
el areadealmacenamientoapuntadapor
rgbValue. El
contenido regresado en rgbValue siempre esta terminado en nulo a menos que se haya usado
SQLSetEnvAttrOparacambiar
el atributo SQL-ATTR-OUTPUT-NTS.
Si la aplicacidnestá
recuperando los datosenvariaspartes,éstadebehacer
los ajustesadecuados(porejemplo,
eliminar el byte de terminacidnen nulo antes de concatenar todas las piezas de nuevo).
El truncamiento de tipos de datos numericos no se reporta si el truncamiento implica dígitos a la
derecha del punto decimal. Siel truncamiento ocurre ala izquierda del punto decimal,se genera un
error.
Códigos de retorno
SQL-SUCCESS
SQL-SUCCESS-WITH-INFO
SQL-ERROR
SQL-INVALID-HANDLE
SQL-NO-DATA-FOUND
Se regresa SQL-NO-DATA-FOUND
la información parauna columna.
cuando la llamada anterior aSQLGetDataO ha obtenido toda
Se regresa SQL-SUCCESS si una cadena de longitud cero es recuperada por SQLGetDataO. Si
éste es el caso, pcbValue contiene O, y rgbValue contiene un terminador nulo.
Si lallamadaa
indefinido.
SQLFetchO falla, SQLGetDataOno
debellamarse
yaque
el resultadosera
4.6 Esquema general de procesamiento de
instrucciones de SQL
En la Figura 4 del capítulo 3 de ésta obra, se observa el formato basic0 de una aplicacidn OBDC,
en ella se aprecia que entre la conexi6n a una fuente de datos y la liberación de los recursos
asociados existe una parte intermedia que consiste en el procesamiento de las instrucciones de
SQL. En esta parte vamos a expandir ése bloque para mostrarlo con mas detalle.
El siguiente esquema ilustra la forma en que se hacen las llamadas a las funciones
de ODBC
dependiendodeltipo de instrucciónde SQLquesetrate.Lasfuncionesrelacionadasconun
50
SELECT,difierendelasqueserelacionanconun
INSERT,UPDATE o DELETE.LaFigura 5
muestralasdistintasfuncionesde
ODBC relacionadasconinstruccionesdeSQL
y el ordende
preferenciadellamadaquetendríanenunaaplicaci6n,dependiendode
los distintostiposde
sentencias de SQL que hay.
Reservar handle de sentencia
SQLAllocStmt()
+
-t
+
I
Ejecutar sentencia directa
SQLSetParamO
SQLExecDirectO
Preparar sentencia
SQLPrepareO
SQLSetParamO
.
+
+
I
I
I
I
Ejecutar sentencia
SQLExecuteO
v
Actualización de datos
(UPDATE, DELETE,
INSERT)
SQLRowCount()
Recuperar datos de una
consulta (SELECT)
SQLNumResultColsO
SQLDescribeCol()
CREATE, DROP,
GRANT, REVOKE
(no requieren función)
O
SQLColAttributes()
SQLBindCol()
SQLFetchO
SQLGetDataO
1
Liberar handle de sentencia
SQLFreeStmtO
SQLTransactO
~~
1
~
Figura 5. Esquema de procesamiento de sentencias.
5 Resumen de funciones de ODBC
Todas las funciones de la API de ODBC empiezan con SQL
y estBn distribuidas dentro de tres
nivelesinclusivos:Núcleo,Level
1 (Nivel 1) y Level 2 (Nivel 2), estaformadeclasificacibnes
conveniente, pero ligeramente artificial desde el punto de vista de programacibn. En 6ste capítulo
y se vera su distribucibn
se harh un recuento de las funciones que conforman la API de ODBC
dentro de los tres niveles de conformidad establecido porSAG
el CLi.
5.1 Niveles de conformidad
El grupo nuclear de funciones (Core API) corresponde a las funciones de la especificacibn de la
WOpenandSQLAccessGroupCallLevelInterface.Losotrosdosgrupos(Niveles
1 y 2) son
extensiones de la SAG CLI specification. La siguiente lista resume la funcionalidad incluida en cada
nivel de conformidad:
Núcleo API
Reservar y liberar handles de ambiente, conexibny sentencia.
Conexibn a fuentes de datos.Uso de sentencias múltiples en una conexibn.
Preparar y ejecutar sentencias SQL. Ejecucibn inmediata de sentencias SQL.
Asignaci6ndeBreasdealmacenamientoparaparbmetrosenunasentenciaSQL
columnas de resultados.
y para
Recuperacibn de datos de un conjunto de resultados. Obtener informacibn sobreel conjunto
de resultados.
Commit o roll back de transacciones.
Recuperar informacibn sobre errores.
51
52
(Nivel 1) Level 1 API
Funcionalidad del núcleo API.
Conexibn a fuentes de datos con cajas de dialogo especificasdel driver.
Puesta y consulta de los valores de las opcionesde sentencia y conexibn.
Envío de parte o de todo el valor de un parametro (útil para datos extensos).
Recuperacibndeparte
extensos).
o detodo el valor de unacolumnaderesultado
(útil paradatos
Recuperacibndeinformacibndecatalogo(columnas,columnasespeciales,estadísticas,
tablas).
y
Recuperacibn de informacibnsobrecapacidadesdeldriver
y de la fuentededatos,tales
como tiposde datos soportados, funciones escalares,
y funciones ODBC.
(Nivel 2) Level 2 API
Funcionalidad del núcleo API y de Level 1 API.
Búsqueda de informaci6n de conexi6n y listado de las fuentes de datos disponibles.
Envío de arreglos de parametros. Recuperacibn de arreglos de resultados.
Recuperacibn del número de parametros y descripcibn de los parametros individuales.
Uso de cursoresnavegables.
Recuperacibn de las formas nativas de las sentencias SQL.
Recuperacibn de informacibn de catalogo (privilegios, llaves y procedimientos).
5.2 Funciones y niveles de conformidad
A continuacibn se hace un recuento de las funcionesde ODBC por nivel de conformidad. Tambien
se da una breve descripci6n para cada una de ellas.
Funciones del núcleo
SQLAllocConnect
Obtiene un handle de conexibn.
SQLAllocEnv
Obtiene unhandle de ambiente. Un handle de ambiente seusa para unao
mas conexiones.
SQLAllocStrnt
Reserva un handle de sentencia.
SQLBindCol
Asigna area de almacenamiento para una columna
y especifica el tipo del dato.
SQLCancel
Cancela una sentenciaSQL.
53
SQLColAttributes
Describe los atributos de una columna del conjunto de resultados.
SQLConnect
Conecta a un driver específico por nombre de fuente de datos, usuario,
y contrasena.
SQLDescribeCol
Describe una columna en el conjunto de resultados.
SQLDisconnect
Cierra la conexibn.
SQLError
Regresa informacibn adicional sobre errores
o de status.
SQLExecDirect
Ejecuta una sentencia.
SQLExecute
Ejecuta una sentencia preparada.
SQLFetch
Regresa una línea de resultados.
SQLFreeConnect
Libera el handle de conexibn.
SQLFreeEnv
Libera el handle de ambiente.
SQLFreeStmt
Finaliza el procesamiento de sentenciasy cierra el cursor asociado,
descarta resultados pendientesy opcionalmente libera todoslos recursos
asociados con el handle de sentencia.
SQLGetCursorName
Regresa el nombre del cursor asociado con el handle de sentencia.
SQLNumResultCols
Regresa el número de columnas en el conjunto de resultados.
SQLPrepare
Prepara una sentencia SQL para su posterior ejecucibn.
SQLRowCount
Regresa el número de líneas afectadas por una instrucci6n insert, update
o delete.
SQLSetCursorName
Especifica un nombre de cursor.
SQLSetParam
Asigna almacenamiento para un pardmetro en una sentencia SQL.
SQLTransact
Confirma o deshace (Commit o Roll Back) una transaccibn.
54
Funciones del Nivel 1
SQLColumns
Regresa unalista de nombres de columnas de las tablas especificadas.
SQLDriverConnect
Conecta aun driver específico mediante una cadena
de conexidn o permite que el
Driver Managery el Driver desplieguenun dialogo de conexi6n para
el usuario.
SQLGetConnectOption
Regresa el valor de una opci6nde conexi6n.
SQLGetData
Regresa parteo toda una columna de una línea de un conjunto de resultados.
(Util para datos extensos.)
SQLGetFunctions
Regresa las funciones soportadas
por el driver
SQLGetlnfo
Regresa informacibn sobre un driver específico y de la fuente de datos.
SQLGetStmtOption
Regresa el valor de una opci6nde sentencia.
SQLGetTypelnfo
Regresa informaci6n sobrelos tipos de datos soportados.
SQLParamData
Regresa el valor de almacenamiento asignado un
a parametro cuyos datos
serdn enviados en tiempo de ejecuci6n.
(Util para datos extensos.)
SQLPutData
Envía parte o todo el dato de un pardmetro. (Util para datos extensos.)
SQLSetConnectOption
Establece opciones de conexibn.
SQLSetStmtOption
Establece opciones de sentencia.
SQLSpecialColumns
Recupera informaci6n sobreel conjunto de columnas que únicamente identifican un
a
registro en una tabla especificada,
y las columnas que son actualizadas automdticamente
cuando cualquier valordel registro es actualizado por una transacci6n.
SQLStatistics
Recupera las estadísticas de una tabla y la lista de indices asociados con
la tabla.
55
Funciones del Nivel 2
SQLBrowseConnect
Regresa niveles sucesivosde atributos de conexi6ny valores de atributos válidos.
Cuando se ha especificadoun valor para cada atributo de conexibn, realiza la conexi6n
a la fuente de datos.
SQLColumnPrivileges
Regresa una lista de columnas ylos privilegios asociados a &stas, para una
o mas tablas.
SQLDataSources
Regresa una lista de las fuentes de datos disponibles.
SQLDescribeParam
Regresa la descripci6n de un parametro específico en una sentencia.
SQLExtendedFetch
Regresa múltiples líneas de resultados.
SQLForeignKeys
Regresa unalista de columnas que son llaves externas (foreign keys),
si tales
columnas existen enla tabla especificada.
SQLMoreResults
Determina si existen m& registros de resultados disponibles
y, si los hay, inicializa
el procesamiento para el siguiente conjunto
de resultados.
SQLNativeSql
Regresa el texto de una sentenciaSQL como fue traducida por
el driver.
SQLNumParams
Regresa el número de parametros enuna sentencia.
SQLParamOptions
Especifica el uso de valores múltiples para parámetros.
SQLPrimaryKeys
Regresa la listade nombres de columnas que son la llave primaria
de una tabla.
SQLProcedureColumns
Regresa lalista de parametrosde entrada y salida, así como las columnas que conforman
el conjunto de resultados arrojado por
los procedimientos almacenados especificados.
SQLProcedures
Regresa la lista de nombres de procedimiento almacenados en una fuente
de datos.
SQLSetPos
Posiciona un cursor dentro de un bloque de registros extraídos
la de
fuente de datos.
SQLSetScrollOptions
Establece las opciones que controlan
el comportamiento del cursor
SQLTablePrivileges
Regresa una lista de las tablasy los privilegios asociados con cada tabla.
56
Para más información
Existe en Internet gran cantidad de sitios relacionados con ODBC. A continuaci6n se mencionan
los m& recomendables, los cuales fueron visitados porel autor de dste trabajo:
En esta direcci6n se encuentra una biblioteca electrbnica en linea sustentada por IBM. En ella
existen varios libros electrónicos con temas computacionales incluyendo ODBC. Cuenta con
un
buscador de libros por tema:
La dirección siguiente es la deun manual en línea proporcionado por la compafiía Solid Information
Technology Ltd. Esta compafiía distribuye un servidor de base de datos llamado SOLID Server que
El manual en línea es la guía y referencia
del programador
tambikn cuenta con un driver de ODBC.
de SOLID Server y presenta varios conceptos importantes de ODBC, asi como la descripcibn de
las funciones de laAPI de ODBC:
httD://www.solidtech.com/support./Da/HTTOC.HTM
Es muyuti1 tambien la dirección del soporte en linea de Microsoft. En ella sepuedeencontrar
y ODBC:
informaci6n relacionada con Visual Basic
httD://suDport.microsoft.com
La siguientetambikn es una biblioteca en línea de IBM:
PARTE II. La biblioteca de funciones
O Sobre la biblioteca de funciones
O Conexion.bas: La biblioteca de funciones
O Uso de las funciones
b Sobre la biblioteca de funciones
En este capítulo se describiran algunos de
los aspectos de la construcción de
la biblioteca de
funciones. Se hablara un poco sobre los pormenores en las que estan cimentadas. Se discutird el
Ambit0 de acción delas funciones de la biblioteca,y que es lo que pueden y no pueden hacer.
6.1 Objetivo y alcance de las funciones
Las funciones que se analizaran en bsta segunda parte sonel resultado de un proyecto que surgió
a raíz de un convenio firmado entre PEMEXREFlNACIdN y la UAM Iztapalapa. El convenio incluía
el desarrollo de sistemas para cubrir problemdticas propias
del corporativo PEMEX. Uno de los
primeros sistemas que se decidió desarrollar implicaba exhaustivos accesos a la base de datos,
cuyoBack-enderaunServidordelnformix
7.0, por lo que el driver utilizado para los accesos
desde el Front-end fue un driver denominado INFORMIX-CLI. Este driver cumple con
los niveles de
conformidad del Núcleo, Nivel 1 y parte del Nivel 2 delaAPIdeODBC.Laherramientade
desarrollofueVisualBasic
4.0, podríapensarsequedadalaherramienta
los mecanismosde
acceso a los datos hubieran sido lógicamente los propios de Visual Basic y Microsoft, como son
RDO o DAO, e incluso tablas vinculadas de Access,lo cual habría facilitado la programación, pero
seencontr6quedados
los requerimientosdevelocidaddeaccesoyrespuesta,asícomola
magnitud del flujo de información, se necesitaba algo mas directo y de mejor rendimiento, por lo
que se optó finalmente por usar
la API de ODBC.
Un servidor, y autor de bsta obra, trabajócasi un mes enel desarrollo de unasuite de funciones en
Visual Basic basadas en la API de ODBC, que fueran de facil uso y comprensión para el resto de
los miembros del equipo de desarrollo. A diferencia de las propias funciones de la API de ODBC,
que pueden resultar oscuras y difíciles de usar para alguien que no haya tenido experiencia conel
lenguajeC, las aquípresentadassonbastantesencillas
y hasta cierto gradointuitivas.Estas
funciones fueron creadas para minimizarel tiempo de aprendizaje delas mismas por el resto de los
59
60
miembros del equipo, el cual habría sido considerable si se hubiera tratado de las funciones de la
API, y también para eficientar el acceso los
a datos.
Cabe resaltar que estas funciones NO proporcionan todas las Características dela API de ODBC,
sólo las mas importantes, como sonla conexión a la fuente de datos,la ejecucidn de sentencias y
la recuperacidn de los datos. Otras funcionalidades propias de la API no fueron implantadas por
razones de tiempo y de limitaciones
del lenguaje (por ejemplo la inexistencia de apuntadores),
entre las funcionalidades no implantadas se tienen el uso de sentencias preparadas, los cursores
navegables, el ligado de columnas con variables, sdlo por mencionar algunas. Sin embargo, las
funciones que se lograron construir cubrieron con éxito las exigencias
del proyecto y funcionaron
muy bien. Con esto no quiero decir que las funciones sean infalibles, es mas, alguien que vea el
código podra encontrar varios fragmentos que son susceptibles de mejorar, lo que quiz2 lleva
al
verdadero objetivo de las funciones: Que sean mejoradas y que implementen mayor funcionalidad
de la API de ODBC, o en su defecto, que estimulen el uso de la API de ODBC. Una de las metas
del autor es llevar M a s funciones a su formamas general: una librería de enlace dinamico o DLL,
para que puedan ser usadas
mas alla de Visual Basic, lo que las convertiría en una verdadera
librería de funciones parala conexión a basesde datos.
6.2 Tipos de Datos Abstractosutilizados
Las definiciones de tipos que se presentan a continuación fueron ideadascon el fin de encapsular
en estructuras sencillas los handles usados por las funciones
de ODBC y presentarlos deuna
formamasamigable,ademas,todaslasestructurascuentan
con camposadicionalesque dan
información importante sobre otras características. También se redefinen los códigos de retorno
para presentarlosen una versión en espaAoly que sean mas faciles de recordar.
El tipo Base de Datos
El tipo BaseDatos encapsula a los handles de ambiente y de conexidn para ser usados de forma
interna por las funciones dela biblioteca de funciones. Una variable de
tipo base de datos alojaen
su interior los handles de ambiente y de conexión obtenidos, el número de tablas que existen
los nombresdelasmismas.Desafortunadamenteenla
dentro de labase dedatos,asícomo
construcción de la función ConectarBD no hubo tiempo de agregarlas dos ÚRimas características,
por lo que 6sta función sólo sirve para portar los handles de ambiente y conexidn y que sean
pasados juntos hacia otras funciones que
los necesiten.
Public Type BaseDatos
ENV As Long
ID As Long
NumTablas As Integer
NomTablasO As String
End Type
'Handle de ambiente
'Handle de conexión
'Número de t a b l a s en la BD
'Nombres de las tablas dela BD
El tipo Registro de SQL
El tipo RegistroSQL es una estructura auxiliaral tipo ConsultaSQL que se ver2mas adelante. En 61
se guardan dentro de un arreglode tamaAo variable (DatosCof) los datos recogidos como cadenas
arrojados por las consultas ejecutadas con
la función HacerConsultaSQL. Tiene tambikn un campo
61
llamado NurnRegAcf, el cual indica el número de rengldn o fila sobre la que esta posicionado el
cursor en el conjunto de resultados. El número de las columnas del conjunto de resultados
se
registra en un campo de la estructura
ConsulfaSQL.
Private Type RegistroSQL
NumRegAct As Integer 'Número de registro actual
Datoscol() As String
'Arreglo de cadenas con los campos del registro
End Type
El tipo Consulta de SQL
Este tipo es el mas utilizado de todos. Las variables de tipo ConsulfaSQL guardan dentro de su
estructura al handle de sentencia usado por las funciones HacerConsulfaSQL, CerrarInsfrucSQL,
SigRegConsulfaSQL y otras. Guardan tambi6n otros datos relevantes a la consulta, 6stos son: la
cadena de la instruccidn SQL, el número de columnas del conjunto de resultados, el número de
registros o renglones del conjunto de resultados, el tipo SQL de cada columna, si las columnas
aceptan o no nulos, los nombresde las columnas regresadas-tal y como estan en la tabla o en la
instrucción SQL-y finalmente una estructura de tipo RegisfroSQL, la cual contiene los datos del
registro sobreel que est6 posicionadoel cursor.
Public Type ConsultaSQL
ID As Long
'Handle de sentencia
InstSQL As String
'Texto de la instrucción SQL
NumCols As Integer
'Número de columnas obtenidas
NumRegs As Long
'Número de registros obtenidos
SQLTipoColO As Integer 'Número del tipo SQL
de la columna
NomTipoCol ( ) As String 'Nombre del tipo SQL
de la columna
AceptaNuloCol ( ) As Long 'Si la columna acepta nulos
o no
NomCol ( ) As String
'Nombres de las columnas
Registro As RegistroSQL 'Datos del registro actual
End Type
Definiciones de constantes para códigos deretorno
Las siguientesdefinicionesdeconstantessonunatranscripci6n
al espaliol delasconstantes
usadas por las funciones de la API de ODBC para los cddigos de retorno; bstas constantes utilizan
el mismo valor num6rico que las otras, por lo que es indistinto
el uso de dstaso las de la API.
'Valores de retorno de las funciones
= -2
Global Const HANDLE-INVALID0 As Long
Global ConstERROR-FUNC As Long = -1
Global ConstEXITO-FUNC As Long = O
Global ConstEXITO-FUNC-CON-INFO As Long = 1
Global Const SIGUE-EJECUTANDO As Long
= 2
Global Const NECESITA-DATOS As Long
= 99
Global ConstNO-HAY-MAS-DATOS As Long = 100
62
6.3 Llamadas a la API de ODBC involucradas
Las funciones de la biblioteca estAn construidas sobre llamadas a la API de ODBC. Las llamadas
utilizadas son en su mayor partelas del núcleo de funciones y en menor grado las del nivell.S610
se us6 una funci6n del nivel2. En la Tabla 15 se relacionan las funciones de la API de ODBC y las
funciones de la biblioteca en las que fueron aplicadas.
Tabla 15. Relación de funciones deODBC usadas en la biblioteca de funciones.
Llamadade ODBC
Niveldeconformidad
SQLAllocEnv
Núcleo
ConectarBD
ConectarBD2
SQLAllocStmt
Núcleo
EjecutarSQL
HacerConsultaSQL
HacerEscrituraSQL
HacerEscDirectaSQL
HacerConsultaSQL
*SQLColAttributesString
Núcleo
HacerConsultaSQL
Núcleo SQLColAttributes
Núcleo
cleo
Núcleo
Funcionesen que se aplica
ConectarBD
ConectarBDZ
NúcleoSQLAllocConnect
Núcleo
API
SQLConnect
ConectarBD
SQLDisconnect
DesconectarBD
ConectarBD
ConectarBD2
SQLError
DescErrorODBC
SQLExecDirect
EjecutarSQL
HacerConsultaSQL
HacerEscrituraSQL
HacerEscDirectaSQL
RepUltimaConsulta
SQLFetch
Núcleo
AntRegConsultaSQL
HacerConsultaSQL
PriRegConsultaSQL
SigRegConsultaSQL
UltRegConsultaSQL
SQLFreeConnect
Núcleo
DesconectarBD
ConectarBD
ConectarBD2
SQLFreeEnv
Núcleo
DesconectarBD
ConectarBD
ConectarBD2
Núcleo
63
Llamada
de
ODBC
Nivel
de
conformidad
API
Funciones en que
se
aplica
CerrarlnstrucSQL
EjecutarSQL
HacerConsultaSQL
HacerEscrituraSQL
HacerEscDirecta
RepUltimaConsulta
SQLFreeStmt
SQLNumResultCols
Núcleo
HacerConsultaSQL
SQLRowCount
Núcleo
HacerEscrituraSQL
HacerEscDirectaSQL
SQLDriverConnect
Nivel 1
ConectarBD2
SQLGetData
Nivel 1
PriRegConsultaSQL
SigRegConsultaSQL
UltRegConsultaSQL
AntRegConsultaSQL
SQLSetConnectOption
Nivel 1
ConectarBD
ConectarBD2
SQLSetStmtOption
Nivel 1
HacerConsultaSQL
RepUltimaConsulta
SQLNumParams
Nivel
2
HacerEscrituraSQL
HacerEscDirectaSQL
* La función SQLColAtfributesStringes un ALIAS para la funciónSQLColAWbutes, la diferencia que tiene la
rgbDesc como ByVal String en lugar de declararlo como
primera de la segunda es que declara el argumento
Any. esto se hizo para poder recuperar atributos de texto en cadenas de caracteres.
Algunas funciones de la biblioteca, como HacerConsulfaSQL, utilizan varias de las funciones de la
API, encambiootras,
sdlo incluyenuna o dosdeellas,como
esel casodelafunción
DescErrorODBC, la cual sdlo usa la funcidn SQLError. Entre m& funciones de la API de ODBC
estén incluidas enel cddigo de una funcidn de la biblioteca, mas compleja
y elaborada es ésta.
Sin embargo, existe una funcidn que noutiliza absolutamente ninguna de las llamadas ala API. Me
refiero a la funcidn ErroresNafivos, la cual obtiene los cddigos de error nativos del driver de ODBC
que se esté manejando.esta funcidn y las demas seran estudiadas en
el siguiente capítulo.
7
Conexion.bas:Labiblioteca de
funciones
En 6ste capítulo se presentaran las funciones que componenla biblioteca de funciones, accesible
paraVisualBasiccon
el M6dulollamado Conexiombas. El m6duloConexioncuentaconlas
definiciones de tipos de datos y los cuerpos de las funciones queya se han estado mencionando.
En los siguientesapartadosseestudiarán6stasfunciones
junto con sus característicasmás
relevantes.
7.1 La función ConectarBD
Esta es la primer funci6n que una aplicaci6n VB debe usar. Con ella se establece la conexi6n a la
fuente de datos dada porel argumento DSN. Se requiere declarar antes una variable como de tipo
BaseDatos para que se utilice como argumento de salida de la funcibn. La variable servirá para
identificar a la fuente de datos a la que se ha hecho conexi6n y que pueda ser usada por otras
funciones.
Sintaxis
CODRET ConectarBD ( DSN
ByVal
UID
ByVal
PSW
ByVal
BD
ByValMostrarErr,
CadErrores
As String, As String, As String, As BaseDatos, As String -
)
65
66
Argumentos de la función
Tabla 16. Argumentos de ConectarBD.
Tipo de Argumento
dato
String
DSN
Entrada
Nombre
fuente
la
datos
de
Uso
Descripción
tal y como
encuentra
se en
el administrador de fuentes de datos de ODBC.
String
UID
EntradaNombredeusuarioválidoreconocido
datos.
String
PSW
Entrada
Contraseña
para
BaseDatos
BD
SalidaldentificadorparalaBasedeDatosa
conexión.
porla fuentede
UD.
la quesehace
Boolean
MostrarErr
Entrada
Bandera
para
indicar
a
la función si desea
se
o no
que
ésta despliegue una ventana
con el mensaje de error
dado por el driver.
String
CadErrores
Salida
Texto
completo
error
del
arrojado
por
función
laprivada
DescErrorODBC,tal y como lo reporta el driver de ODBC.
Comentarios
La función ConectarBD es la primer funcidn de la biblioteca de funciones que se debe utilizar para
realizar un acceso a base de datos. Despues de 6sta funcibn, generalmente se usan las funciones
HacerConsultaSQL o EjecutarSQL.AIfinalizar las consultassedebecerrarlaconexidnconla
función DesconectarBD.
Códigos de retorno
EXlTO-FUNC
EXITO-FUNC-CON-INFO
ERROR-FUNC
7.2 La función ConectarBDZ
Esta función tiene el mismo propósito que la función ConectarBD,la única diferencia con M a es la
forma en la que se realiza la conexión. Con la función ConecfarBD2 en lugar de especificar
por
separado el nombre de la fuente de datos, el nombre de la cuenta de usuario y la contraseña,
estos datospueden incluirse dentrodeunacadenadeconexión,
la cualserapasadacomo
argumento de entrada a la función. Si la función determina que los datos para la conexión no son
suficientes desplegara una ventana propia del driver de ODBC utilizado que le pedira al usuario la
informacióndeconexiónfaltante.
Si el usuario elige CANCELARenlaventanadesplegada
la
funcibn retornará ERROR-FUNC.
67
Sintaxis
CODRET ConectarBD2 ( ByVal
CadCon
BD
ByValMostrarErr,
CadErrores
1
As
String, -
As BaseDatos, -
As String
Argumentos de la función
Tabla 17. Argumentos de ConectarBDZ.
Tipo de dato
Argumento
Uso
Descripción
String
CadCon
Entrada
Cadena
conexión
de para
efectuar
el acceso. Los valores
típicos son: DSN, UID y PWD
BaseDatos
BD
Salida
ldentificador
para
Base
la
conexión.
de que
hace
Datos
se
laa
Boolean
MostrarErr
Entrada
Bandera
para
indicar
a
la función si se
desea o no
que
ésta
despliegue una ventana con
el mensaje de error dado por el
driver.
String
CadErrores
Salida
Texto
completo
del error
arrojado
función
por
la privada
DescErrorODBC, tal y como lo reporta el driver de ODBC.
Comentarios
La funcidn ConectarBD2 es la primer funcidn de la biblioteca de funciones que se debe utilizar
alternativamente a ConecfarBD para realizar un acceso a base de datos. Despues de esta funcidn,
generalmente se usan las funciones HacerConsultaSQL o EjecufarSQL. AI finalizar las consultas
se debe cerrarla conexidn conla funcidn DesconecfarBD.
La cadenade conexi6n es de la forma:
"DSN=< fuente de dafos>;UlD=<usuario>;PWD=<confraseAa>"
podríamostenerporejemplolacadena:
"DSN=contable;UID=shiranui;PWD=mai", enlaquese
declaraquelafuentededatossellama
contable, el usuariocon el quesepide el accesoes
shiranui y sucontrasena es mai. Sepuedenagregaralacadenavalorescomo:SERVER,
DATABASE y otros, dependiendodel driver de ODBC quese use.
Si alguno de los valores no es correcto se desplegara la ventana de conexidn para corregir la
informacidn. Es posiblepasar
unacadenavacía
y esperarque
el usuarioproporcionela
informacidn correcta usandola ventana que es desplegada porel driver a traves de la funcidn.
Códigos de retorno
EXlTO-FUNC
EXITO-FUNC-CON-INFO
ERROR-FUNC
68
7.3 La función HacerConsultaSQL
La funci6n HacerConsultaSQL tiene la finalidad de procesar instrucciones de consulta (SELECT'S),
y de proporcionar un identificador para el conjunto de resultados generado. Se debe llamar a la
funci6n ConectarBD antes que a HacerConsultaSQL. Despues de 6sta funcidn, generalmente se
usan lasfuncionesdenavegaci6n
de resultados: PriRegConsultaSQL,AntRegConsultaSQL,
SigRegConsulfaSQL y UltRegConsultaSQL. Opcionalmente
puede
se usar
la función
CerrarlnsfrucSQL despues de procesarlos datos.
Sintaxis
CODRET HacerConsultaSQL ( BD
SQL ByVal
CSQL
ByValMostrarErr,
CadErrores
As BaseDatos, As String,
AS ConsultaSQL,
As String
-
-
)
Argumentos de la funcidn
Tabla 18. Argumentos de HacerConsultaSQL.
Tipo de dato
Argumento
Uso
Descripción
a la que
hecho
ha
se
BaseDatos
BD
Entrada
ldentificador
base
la
de
datos
de
conexión
String
SQL
Entrada
instrucción
Cadena
lade
SELECT
SQL
ejecutar.
a Regularmente
un
ConsultaSQL
CSQL
Salida
ldentificador
instrucción
lade ejecutada.
Una
vez
ejecutada
la instrucciónlos valores de sus campos contienen datos
válidos sobreel conjunto de resultados como: numero de
columnas, de renglones, etc.
Boolean
MostrarErr
Entrada
Bandera
para
indicar
a
la función si se
desea o no
que
ésta
despliegue una ventanacon el mensaje de error dadopor el
driver.
String
CadErrores
Salida
Texto
completo
del error
arrojado
función
por
la privada
DescErrorODBC, tal y como lo reporta el driver de ODBC.
Comentarios
Se requiere declarar una variable como
de tipo ConsultaSQL para que se pase como parametro
de
salida de la funcidn. La variable se utilizara en otras funciones de la biblioteca ya que identifica al
conjunto de resultados obtenidos con la funcibn. Las funciones de navegaci6n de resultados son
un ejemplo de las funcionesque usan 6sta variable.
Aunque es posible llamar a esta funci6n con instrucciones de escritura no es muy recomendable,
pues al tratar la funci6n de determinar los parámetros asociados a un conjunto de resultados se
tendran errores. En general la sentencia de escritura se ejecutara bien pero la funci6n regresará
EXITO-FUNC-CON-INFO.
69
Códigos de retorno
EXITO-FUNC
EXITO-FUNC-CON-INFO
ERROR-FUNC
HANDLE-INVALID0
7.4 La función HacerEscDirectaSQL
Esta función se creó con la intención de ejecutar operaciones de escritura hacia la base de datos,
comosonsentenciasINSERT,DELETE
y UPDATE.Utilizatambiknunavariabledetipo
ConsultaSQL pero sólo para recoger algunos datos de inter& como
el número de parametros en la
sentencia y la cuenta de líneas afectadas en la escritura, esto es, para el INSERT cuantas líneas
se insertaron, para el DELETE cuantas se borraron y para el UPDATE cuantas se actualizaron.
Puede ejecutar tambi6n sentencias SELECT pero no registrara en la variable toda la informacitm
que se obtendría con la funciónHacerConsultaSQL.
Sintaxis
CODRET HacerEscDirectaSQL ( BD
As BaseDatos, SQL ByVal
As String,
CSQL
As ConsultaSQL, ByValMostrarErr,
CadErrores
As String )
Argumentos de la funci6n
Tabla 19. Argumentos de HacerEscDirectaSQL.
Descripción
Tipodato
de
Argumento
Uso
BaseDatos
BD
Entrada
ldentificador
de
conexión
la base
datos
de a
la que
se
hecho
ha
String
SQL
Entrada
Cadena
de
la instrucción
ejecutar.
SQL
aINSERT,
DELETE
o UPDATE.
ConsultaSQL
CSQL
Salida
ldentificador
de
la instrucción
ejecutada.
Una
vez
ejecutada
la instrucción, los valores de sus campos contienen datos
de interés: número de paremetros
y número de líneas
afectadas.
Boolean
MostrarErr
Entrada
Bandera
para
indicar
a
ésta
la función si se
desea o no que
despliegue una ventana con
el mensaje de error dado por
el
driver.
String
CadErrores
Salida
Texto
completo
error
del
arrojado
por
la función
privada
DescErrorODBC,tal y como lo reporta el driver de ODBC.
70
Comentarios
Si se utiliza Bsta funcidn para ejecutar una sentencia SELECT se corre el riesgo de perder datos
importantes sobre el conjunto de resultados. Esta funci6n es conveniente sblo para sentencias de
escritura.
Códigos de retorno
EXITO-FUNC
EXITO-FUNC-CON-INFO
ERROR-FUNC
HANDLE-INVALID0
La función HacerEscrituraSQL
Estafunciónen
un principiosepens6usarpara
la ejecuci6ndetransaccionesysentencias
preparadas,elloimplicaba
el uso internodelasfunciones
dela API de ODBC SQLPrepare,
SQLExec, SQLBindCol, SQLTransac y otras, pero por razones de tiempo no fue posible lograrlo y
ahora es una copia dela funci6n HacerEscDirectaSQL.
7.5 La función EjecutarSQL
La funci6n EjecutarSQL es mas practica que las funcionesHacerEscrituraSQL y HacerEscDirecta,
debido a que no requiere declarar antes una variable de tipo ConsultaSQL. Su uso primordial es
paraejecutarcualquierinstrucci6ndeSQLqueno
seaSELECT.Estoincluyeinstrucciones
INSERT, DELETE, UPDATE, CREATE, REVOKE, GRANT, EXECUTE
entre otras. Como no usa
la instruccibn,simplemente
variablesdetipo ConsulfaSQL noregresainformaci6nrelevantea
ejecuta las instrucciones y hace el chequeo de errores, regresando la informacidn de &tos si se
presentan.
Sintaxis
CODRET EjecutarSQL ( BD
ByVal
SQL
ByValMostrarErr,
CadErrores
As BaseDatos, As S t r i n g , As
String -
)
Argumentos de la función
Tabla 20. Argumentos de EjecutarSQL.
Tipo de dato
Argumento
Uso
Descripción
BaseDatos
BD
Entrada
ldentificador
base
de
lade
datos
que
la
ha
hecho
se
a
conexión
71
Uso
dato
Tipo
Argumento
de
String
SQL
Boolean
MostrarErr
String
CadErrores
Descripción
Entrada
la
Cadena
de
instrucción SQL a ejecutar.
Entrada
Bandera para indicar a la función si
se desea o no que Bsta
despliegue una ventana con
el mensaje de error dado porel
driver.
Salida
Texto
completo
del error arrojado por la función privada
DescErrorODBC. tal v como lo reDorta el driver de ODBC.
Comentarios
La función es capaz de ejecutar cualquier sentencia de SQL reconocida por el driver de ODBC,
inclusive sentencias SELECT. El problema con las sentencias SELECT es que no existe ninguna
referencia haciael conjunto de resultados generado por lo que no es posible accesar
los datos.
Códigos de retorno
EXITO-FUNC
EXITO-FUNC-CON-INFO
ERROR-FUNC
7.6 Las funciones de navegación de resultados
Las funciones para navegar por
el conjunto de resultados son
las siguientes:
AntRegConsultaSQL-Regresa el cursor al registro anterior del que esta posicionado.
SigRegConsulfaSQL-Avanza el cursor al siguiente registro enel conjunto de resultados.
PriRegConsultaSQL-Mueve el cursor al primer registrodel conjunto de resultados.
UltRegConsulfaSQL-Mueve el cursor al ultimo registrodel conjunto de resultados.
Estas funciones se llaman despues de que se ha ejecutado
con exit0 la funcidn HacerConsultaSQL
para una sentencia SELECT. AI ir moviendo el cursor con dstas funciones los datos del registro
sobre el queseposicione
el cursorestarandisponiblesdentro
de la estructuradeconsulta
ConsultaSQLensucampoRegistro.DafosCol.Recordemosque
DatosCol es un arreglode
cadenas cuya longitud correspondeal número de columnas enel conjunto de resultados y en este
arreglo residen los datos.
Sintaxis
CODRET AntRegConsultaSQL
(CSQL AsConsultaSQL,
CODRET SigRegConsultaSQL(CSQL AsConsultaSQL,
CODRET PriRegConsultaSQL(CSQL As ConsultaSQL,
CODRET UltRegConsultaSQL
(CSQL AsConsultaSQL,
ByVal MostrarErr,CadErr AsString)
ByVal MostrarErr,CadErr As String)
ByVal MostrarErr,CadErr AsString)
ByVal MostrarErr,CadErr AsString)
72
Argumentos de la función
Tabla 21. Argumentos de las funciones de
navegación de resultados.
Tipodato
de
Argumento
ConsultaSQL
CSQL
Entrada
Boolean
MostrarErr
String
CadErr
Salida
Texto
completo
Uso
Descripcidn
ldentificador de la consulta
ejecutada.
Entrada
Bandera
para
indicar a la funci6n se
sidesea
o no que
ésta
despliegue una ventana con
el mensaje de error dado por
el
driver.
del error arrojado por la función
privada
DescErrorODBC, tal y corno lo reporta el driver de ODBC.
Comentarios
Si el conjunto de resultados esta vacío cualquierade las funciones regresar2 el cbdigo de retorno
NO-HAY-MAS-DATOS. Si el cursor esta en el último registro y se hace una llamada a la funcibn
SigRegConsultaSQLlafuncibnregresaraNO-HAY-MAS-DATOS.Peronopasa
lo mismo si el
cursor est& en el primer registro y se llama a la funcibn AntRegConsultaSQL, en este caso la
función reconoceal primer registro y deja el cursor en el mismo lugar regresando EXITO-FUNC. Si
se ha cerrado el conjunto de resultados con CerrarlnstrucSQL o alguna otra razbn, las funciones
regresaran HANDLE-INVALIDO.
Códigos de retorno
EXITO-FUNC
EXITO-FUNC-CON-INFO
0
ERROR-FUNC
NO-HAY-MAS-DATOS
0
HANDLE-INVALID0
7.7 La función CerrarInstrucSQL
CerrarlnstrucSQL tiene como única funcionalidad liberarlos recursos asociados a las variables de
tipo ConsultaSQL. Despues de usaresta funcibn se debe llamar nuevamente a HacerConsultaSQL
para obtener una nueva estructura de tipo ConsultaSQL para utilizar.
Sintaxis
CerrarInstrucSQL (CSQL As ConsultaSQL)
73
Argumentos de la función
Tabla 22.Argumentos de CerrarlnstrucSQL.
Tipo de Argumento
dato Descripcidn
Uso
ConsultaSQL
CSQL
Entrada
ldentificador de la instrucción SQL
desea
que
secerrar
para liberar los recursos asociados.
Comentarios
El uso de Bsta funcidnes opcional ya que las funciones HacerConsultaSQLy HacerEscDirectaSQL
reservan recursos para la sentenciaen forma interna cada vez que son llamadas. Si bien se puede
usar CerrarlnstrucSQL al final del procesamiento de sentencias, tarnbien la funcidnDesconectarBD
realiza el cierre automAtico de todas las sentencias asociadas con la base de datos que se le pasa
como parámetro.
Códigos de retorno
Esta función no regresa ningún cddigo.
7.8 La función DesconectarBD
Esta es la última funcidn que debe llamar una aplicacidn despues de terminar
el acceso a los datos
deunafuentededatos.Lafuncidn
DesconectarBD desconecta a la aplicacidn de la fuente de
datos y libera los recursos asociados a esta. Es importante desconectar todas las sesiones con el
servidordebasededatosyaquealgunostiposdeellosempleanprocesosparamanejarla
conexidn, y si no se presenta la desconexidn por parte del cliente 6stos procesos pueden durar
indefinidamente corriendo en elserver-side.
Sintaxis
DesconectarBD (BD As BaseDatos)
Argumentos de lafunción
Tabla 23.Argumentos de DesconectarBD.
Tipo de dato
Argumento
Uso
Descripcih
BaseDatos
BD
Entrada
ldentificador
base
lade
terminar la conexi6n.
de datos
con
la cualdesea
se
Comentarios
Esta funcidn puede tambiBn desplegar los mensajes de error generados por el driver en caso de
presentarseerroresduranteladesconexidndelafuente.Estosemanejadeformainterna
mediante la funcidn privadaDescErrorODBC con su argumentoMostrarError puesto aTRUE.
74
Códigos de retorno
Esta funciónno regresa ningún cddigo de retorno.
7.9 La función ErroresNativos
La funcidn ErroresNativos akla los números de error de los errores presentados por el driver o el
driver manager a partirdel mensaje de error capturadoen el argumento de salida dela mayoría de
las funciones: CadErrores. Esta misma cadena se usa como argumento de entrada de la función
ErroresNativos la cual regresa otra cadena conlos números de error capturados, separados por
un
carhcter 'Y. Estafuncidnpuedeusarseparatraducir
los errores del lenguajeenelqueson
presentados al espailol, o bien para interpretarlos como mas convenga.
Sintaxis
String ErroresNativos(ByVa1 MsgError
As String)
Argumentos de la función
Tabla 24. Argumentos de ErroresNativos.
Tipo de dato Argumento
String
MsgError
Uso
Descripcibn
Entrada
Cadena
con el mensaje de error
tal y como lo está en el
argumento de salida Cad€mres de las otras funciones.
Comentarios
Si el mensaje de error es una cadena vacía, la funcidn
tambiBn regresa una cadena vacía.Se debe
usar como entradael valor del argumento de salidaCadErrores.
Códigos de retorno
La función regresa una cadena con
los números de error separados por"/"
7.10 Las funciones privadas
Dentro de la biblioteca Conexion, se crearon dos funciones de carActer privado para uso exclusivo
de las otras funciones públicas,una es la que se encargadel manejo de los errores y automatizala
presentación delos mismos, Bsta es la funciónDescErrorODBC. La otra es una funcidn que se
usa
para repetir la consulta asociada a un handle de sentencia, su principal objetivo es el de mover el
cursornuevamente al inicio del conjuntoderesultados, la funcidn RepUltimaConsulta. Ambas
funciones se describen a continuación.
75
La función privada DescErrorODBC
La funcidn DescfrrorODBC se declard como Private con el fin de que sdlo pueda ser utilizada por
lasfunciones del mddulo Conexion.bas, puestoqueutilizacomoargumentosdeentrada
los
handles de ambiente, conexidn y sentencia encapsulados en los tipos de datos descritos en el
capítulo anterior. Pero es posible redeclarar 6sta funcidn como Public y usar los handles antes
mencionados. Para el de ambiente: BaseDatosENV, para el de conexidn: BaseDatoslD y para el
de sentencia: ConsultaSQL.ID. El prototipo de la funcidn es
el siguiente:
String DescErrorODBC (ByVal rhenv&, ByVal rhdbc&, ByVal rhstmt&,
ByVal MostrarErr) As String
El ampersand
en los argumentos indica que son de tipo Long. El argumento MostrarErr es de
tipo Boolean y sirve para indicarle a la funcidn si se desea (TRUE) que despliegue o no (FALSE)
una ventana con el mensaje de error generado. La funcidn regresa una cadena con
el texto del
error dado por el drivery el driver manager.
'I&"
La función privada RepUltimaConsulta
El objetivo de 6sta funcidn es el de repetir la consulta asociada con la estructuraConsultaSQL. La
funcidn utiliza el campo lnstSQL de dicha estructura para volver a ejecutar la instrucci6n SQL. El
prototipo de la funcidn esel siguiente:
CODRET RepUltimaConsulta(CSQLAs ConsultaSQL, ByVal MostrarErr, CadErrS)
El signo "$" en el argumento CadErr indica que es de tipoString. El argumento MostrarErr cumple
el mismo objetivo que en DescErrorODBC. La funcidn regresa los c6digos de retorno conocidos:
y HANDLE-INVALIDO. El uso que se
EXITO-FUNC, EXITO-FUNC-CON-INFO, ERROR-FUNC
le dadentrodelasfuncionespúblicases
el deposicionar el cursornuevamente al inicio del
conjunto de resultados, no en el primer registro, sino uno antes de este. Por ejemplo la funcidn
PriRegConsultaSQL primero llama aRepUltimaConsultay despues a la funcidn de la API
de ODBC
SQLFetch, con lo que el cursor queda en
el primer registrodel conjunto de resultados.
8
USO
de las funciones
En este capítulosever2nenaccidnlasfuncionesde
la bibliotecadefuncionesmediante una
aplicacidn Visual Basic de ejemplo. Se describir2 brevemente
el esquema de uso de las mismas en
una aplicacidn, como se hizo con las funciones de
la API de ODBC.
8.1 Un ejemplo sencillo
En esta parte se dar2 unlistado de una aplicacidn VisualBasic en la cual
se hace la conexión a una
base de datos, se crea una tabla, se insertan dos registros en la misma, se hace una consulta en
ella y sedespliegan los resultados.Posteriormenteseeliminalatabla,secierralaconexidn
y
termina el programa.
Supongamosqueexisteunabase
de datosdeMicrosoftAccessllamada
coneccion. En ella
crearemos la tabla tgrueba con los siguientes campos: id, datol y dato2. El primero de tipo
numkrico que ser2 la llave primaria y los dos restantes de tipo texto con una longitud de 20 y 30
caracteres respectivamente. La instruccidn SQL de la Microsoft Jet database engine para crear la
tabla en la base de datos de Access es:
CREATE
TABLE
t-prueba (
i d INTEGERCONSTRAINT
d a t o l TEXT ( 2 0 ) ,
d a t o 2 TEXT ( 3 0 )
c o n s t l PRIMARY
KEY,
);
Despues de creada la tabla insertamos dos registros con las siguientes instrucciones
INSERT:
INSERT INTO t-prueba
INSERT INTO t-prueba
VALUES ( 1 , ' p r u e b a l ' ,
VALUES ( 2 , ' p r u e b a 2 ' ,
77
'texto pruebal');
'texto prueba2');
7%
La consulta esla siguiente:
SELECT * FROM t-prueba WHERE id= 1;
Para eliminar la tabla hacemos:
DROP TABLE t-prueba;
Con lo anterior ya estamos en condiciones de crear nuestra aplicaci6n en VisualBasic usando las
funciones de la biblioteca. Todo el código lo pondremos dentro del metodo Click de una forma de
VisualBasicquepordefaultsera
Forml. En la formaincluiremostrescajasdetextopara
el
despliegue delos datos. Tambikn les dejaremos sus nombres por omisibn:
Textl, Text2 y Text3.
El códigoquesemuestraacontinuaci6nhaceusodelassiguientesfunciones:ConectarBD2,
EjecutarSQL, HacerEscDirectaSQL, HacerConsultaSQL, SigRegConsultaSQL, CerrarlnstrucSQLy
DesconectarSD, las cuales son la mayoría de las funciones de la biblioteca. El c6digo es pues el
por simplicidad.
mostrado enel Listado 8. El manejo de errores se omite
Listado 8. Ejemplo de uso de las funciones de la biblioteca Conexion.bas.
Private Sub Form-Click()
'Declaramos las variables necesarias
DimBaseAsBaseDatos'Identificadordelabasede
datos
Dim ConSQL As ConsultaSQL 'Identificador
de la consultaSQL
Dim CodRetAsInteger'Código
de retorno de lasfunciones
Dim
Error
As
String
'Cadenas
de
error
generadas
Dim sql As String
'Instrucción
SQL
'Se realiza la conexión
y obtenemos el identificador de base de datos
CodRet = ConectarBDZ("DSN=coneccion;", Base, True, Error)
'Se crea la tabla de ejemplo
sql = "CREATE TABLE t-prueba ( "
sql = sql + "id INTEGER CONSTRAINT constl PRIMARY KEY,"
s q l = sql + "dato1 TEXT (20), "
s q l = sql + "dato2 TEXT
(30)"
sql = s q l +
CodRet = EjecutarSQL(Base, sql, True, Error)
' I ) ;I'
'Se insertan dos registros:
'Uno con HacerEscDirecta y el otro con EjecutarSQL
sql = "INSERT INTO t-prueba VALUES (1, 'pruebal' , 'texto pruebal'
) ;"
CodRet = HacerEscDirectaSQL(Base, sql, ConSQL, True, Error)
Debug.PrintConSQL.NumCols'Númerodeparámetros
Debug.Print ConSQL.NumRegs 'Número
de registros afectados
sql = "INSERT INTO t prueba VALUES
(2, 'prueba2', ' texto prueba2
' ) ;"
CodRet = EjecutarSQLIBase, sql, True, Error)
'Se realliza la consultay obtenemos su identificador en ConSQL
* FROM t-prueba WHERE id = 1 ; "
CodRet = HacerConsultaSQL(Base, sql, ConSQL, True, Error)
Debug.Print ConSQL.NumCols 'Número
de columnas obtenidas
Debug.Print ConSQL.NumRegs 'Número
de registros leidos
sql = "SELECT
'Se obtiene la información
CodRet = SigRegConsultaSQL (ConSQL,
True, Error)
'Se despliegan los datos: nombre de columna y contenido
79
Text1
Text2
Text3
=
=
=
ConSQL.NomCol(1) + " : " + ConSQL.Registro.DatosCol(1)
+ ConSQL.Registro.DatosCol(2)
ConSQL.NomCol(2) +
+ ConSQL.Registro.DatosCol(3)
ConSQL.NomCol(3) +
'I:"
'I:"
'Se cierra la instrucción actual para indicarle
al driver que la
'tabla referenciada en la sentencia identificada por ConSQL
no ya
'está siendo usaday así poder eliminarlacon DROP TABLE. De lo
'contrario el driver emite un mensaje de error indicando que la
uso
'tabla aún está en
CerrarInstrucSQL ConSQL
'Eliminamos la tabla
sql = "DROP TABLE t-prueba;"
CodRet = EjecutarSQL(Base, sql, True, Error)
'Se cierra la conexión
DesconectarBD Base
End Sub
Obs6rvese lo sencilloy compacto del cddigo y comparese con la versatilidad que 6ste tiene.
En un
grupo reducido de líneas logramos hacer una conexidn con una basede datos, creamos una tabla
y le insertamos registros, despues leímoslos registros y los presentamos, para finalmente eliminar
la tabla de la base de datos y cerrar la conexidn. Si se hubieran usado las funcionesde la API de
ODBC directamentehabríanresultadoquiz3
mas de dospaginas de cddigo,sinmencionar lo
complicado que sería.
Algoimportantequehayqueresaltar
del cddigoeslanecesidaddecerrar
la instruccidnde
consulta que asocia a la tabla
tdrueba mediante la funcidn CerrarlnstrucSQL, pues mientras el
driver mantenga handles activos asociados con una tabla 6ste interpreta que dicha tabla aún se
encuentra en uso, por loquenoesposiblerealizarningunaoperacidnDDL(DataDefinition
Language) que modifique la estructura dela tabla asociada. Para demostrar esto podemos eliminar
la siguiente líneadel cddigo:
CerrarInstrucSQL ConSQL
AI ejecutarse la sentencia DROP TABLE mediante la funcidn
EjecutarSQL siguiente, con su opcidn
de mostrar error puesta a verdadero,el driver de Microsoft Access desplegarael mensaje de error
que semuestraen la figura 6 . Ndteseque el mensajedeerrorcontienetodos
los elementos
discutidos en el apartado 6 del capítulo 3, ademas de un dato adicional que es el número de error
con el que el driver de Microsoft Access clasifica aese error, tal inforrnacidn tiene la leyenda "Error
nativo:" seguido porel número de error. El argumento de salida CadError contiene exactamente el
mismo texto que el mostrado por la ventana de error. Para aislar los números de error úsese la
función ErroresNativos de la bibliotecade funciones.
Figura 6. Mensaje de error del driver de Microsoft
Access.
80
Si se desea llevar a la practica
el ejemplo aquí estudiado se debe crear un proyecto nuevo de
VisualBasic y dibujar una forma que por omisi6n debera llamarse Forml , despues a la forma se le
agregan tres cajas de texto o Text Boxes sin cambiarles el nombre. En el metodo Click de Forml
se introduce todoel c6digo arriba listado. Para hacer uso
de las funcionesde la biblioteca se deben
añadir al proyecto dos mddulosmuy importantes: ODBC32.basy Conexion.bas, el primero tiene las
declaracionesdelasfunciones
de laAPI de ODBC quesonutilizadasdentro
del m6dulo
Conexion.bas, el cual cuenta con los prototipos de las funciones de la biblioteca de funciones. Los
listados de los m6dulos ODBC32.basy Conexion.bas se muestranen los apkndices Ay B.
8.2 Esquema de uso de las funciones
Dentro del c6digo en el apartado anterior se puede adivinar cual es el orden de llamada a las
funciones de la biblioteca de funciones. A continuaci6n se describira rapidamente el formato que
seguiríaunaaplicaci6nVisualBasicqueutilicelasfunciones
del m6dulo CONEXION. Este
esquema es parecido en cuanto a orden al mostrado en la Figura 5 del capitulo 4, referente a las
funciones de la API de ODBC. En general el formato de uso de las funciones de la API de ODBC
es la combinaci6nde los esquemas mostrados enlos capítulos 3 y4. Se nota a simple vistaque el
esquema de uso de funciones que ahora nos ocupa resulta mas compacto. La Figura7 muestra la
secuencia que normalmente se sigue al usar las funciones de la biblioteca de funciones para la
conexi6n a basesde datos abiertas.
ConectarBD
ConectarBD2
+
+
+
AntRegConsultaSQL
SigRegConsultaSQL
PriRegConsultaSQL
UltRegConsultaSQL
+
+
v
HacerEscDirectaSQL
HacerEscrituraSQL
HacerConsultaSQL
EjecutarSQL
,
*
ErroresNativos
-
+
+
v
CerrarInstrucSQL
J
DesconectarBD
Figura 7. Esquema de uso delas funciones del m6dulo CONEXION.
81
AI igual que como sucede con API,
la lo primero que se requiere es realizar
la conexi6n con la base
de datos, esto se logra con ConectarBD o ConectarBD2, despues se debe elegir entre hacer una
consulta con HacerConsultaSQL, realizar una operaci6n de escritura con HacerEscDirectaSQL o
HacerEscrituraSQL,o cualquier otro tipo de instrucci6nSQL con EjecutarSQL. Si se decidi6 hacer
una consulta lo que sigue es usar cualesquiera de las funciones de navegaci6n de resultados, es
decir, PriRegConsultaSQL, SigRegConsultaSQL,AntRegConsultaSQL y UltRegConsultaSQL. Es
posiblequesenecesiteliberarrecursosasociadosa
una consultacon
CerrarlnstrucSQL.
Finalmentese libera la conexi6n con DesconectarBD. Dentro de todo el procesosepueden
obtener los númerosdeerrorcuando
la aplicaci6n setopeconestosusando
la funcibn
ErroresNativos.
8.3 Nuevamente el manejo de errores
AI igual que las funciones de ODBC, las de
la biblioteca de funciones tambien cuentancon c6digos
de retorno para indicar la forma en que se ejecut6 la funcibn,
y como ya se vio en el capítulo
anterior, cada funcibn de la biblioteca cuentacon un conjunto fijo de c6digos de retorno. Sabiendo
esto ya conocemos así los c6digos que se pueden esperar para cada funci6n (para las funciones
que regresan c6digos de retorno), y como se hizo con las funciones de ODBC tambien en dste
caso se puede realizar un manejo sencillo de errores, usando bloques I[ Then o bloques Select,
Case. El fragmento de c6digo mostradoen el Listado 9 dará mayor claridad a las palabras.
Listado 9. Ejemplo de manejo de errores.
Dim Base As BaseDatos
Dim CodRet As Integer
Dim CadConAs String
Dim ErroresAs Strin
CadCon = "DSN=coneccion;UID=ukyo;PWD=shampoo;"
CodRet = ConectarBD2 (CadCon, Base,
True, Errores)
if CodRet <> EXITO-FUNC Then
su propio mensajede error
'La función despliega además
'pues la bandera mostrar error esta puesta a TRUE
MsgBox "Error al intentar conectar ala base de datos"
Exit Sub
Else
MsgBox "La conexión se realizó con éxito
"
End I f
Esta es la forma más sencilla de tratar los errores,puessiemprepodemosusarlabandera
MostrarError en las funciones que la tengan para que la funci6n despliegueel mensaje de erroren
forma automática, y probar los c6digos de retorno para bifurcar la ejecuci6n del programa como
más convenga. Silo que se desea es una revisidn más exhaustiva podemos usar un bloqueSelect
Case en lugar del If Then y probar todos los casos.
Para un análisismás detallado de los errores contamos tambiencon la funci6n ErroresNativos,con
la que podemos aislarlos números de error y tomar acci6n para cada caso, sabiendo
de antemano
que error implica cada número conla documentacidn del driver deODBC que se utilice. Tomemos
82
por ejemplo el error de la Figura 6. El error nativo del driver de Microsoft Access que identifica la
condici6n de que una tabla está siendo usada por otra personao proceso es el error que tiene el
número -1304. Sabiendo esto podemos hacer:
Dim
NumerosErrorAs String
NumerosError = ErroresNativos(MsgError)
If InStr(NumerosError, "-1304") > O Then
o proceso"
MsgBox "La tabla está siendo usada por otra persona
'Tomar acción respecto al error. Por ejemplose puede
'cerrar la instrucción con CerrarInstrucSQL
Exit Sub
End If
Lo que es más amigable que el mensaje de error en ingles mostrado en la Figura 6, ademas,
permite tomar decisiones más precisas que simplemente usando los c6digos de retorno. Para el
listadoanteriorpodemos,porejemplo,cerrar
la instrucci6nqueinvolucrea
la tabla y probar
nuevamente con la instrucci6n que gener6
el error.
PARTE 111. JDBC
O Introducción a JDBC
O Conexión JDBC a bases de datos
9
Introducción a JDBC
La Java Database Connectivity o JDBC, es junto con Java de Sun Microsystems uno de los hitos
en herramientasde desarrollo mas innovadores en los tiemposde la red de redes o Internet. JDBC
es al igual que ODBC una API de desarrollo, pero especialmente creada parael lenguaje Java. En
los capítulos que forman el resto de este trabajo se hara un breve estudio de la API de JDBC. El
objetivo de 6sta tercera parte es
el de introducir la API de JDBC y proporcionar los elementos
mínimos para crear aplicaciones Java capaces de conectarse a bases
de datos abiertas. Para este
capítulo se hacela suposición de que el lector tiene algunos conocimientos sobre
el lenguaje Java.
9.1 Que es JDBC
JDBC es una API de Java que permite ejecutar instrucciones SQL (Structured Query Language:
Lenguajeestructuradodeconsultas),queesunlenguaje
de alto nivel paracrear,manipular,
examinar y gestionar bases de datos relacionales. Consiste de un conjunto de clases e interfaces
escritasen el lenguaje de programaciónJava.Comoveremosmasadelanteparaque
una
aplicación pueda hacer operaciones en una base de datos, ha de tener el correspondiente Driver
que conecte la aplicaci6n con esta. Así puesla API de JDBC es basicamente un paquetede JAVA
(javasql) que contiene un conjunto de clases e interfaces escritas
en JAVA. JDBC proporciona una
APIcomúnparadesarrolladoresdeherramientasdebasesdedatosyhaceposibleescribir
aplicaciones de basesde datos usando Java puro.
Con JDBC, es facil enviar instrucciones SQL a virtualmente cualquier base de datos relacional. En
otras palabras, con la API de JDBC, no es necesario escribir un programa que accese a una base
dedatosSybase,otroqueacceseaunabase
de datosOracle,otroparaunabasededatos
Informix, y así consecutivamente. Uno puede escribirun solo programa ,usandola API de JDBC, y
el programa sera capaz de enviar instrucciones de SQL a las bases de datos apropiadas. Y, con
una aplicación escrita en el lenguaje de programación Java, tampoco hay que preocuparse de
a5
86
escribir diferentes aplicaciones para que corran en distintas plataformas. La combinaci6n de Java
y
JDBC permite al programador escribirel programa una vez y correrlo practicamente donde sea.
Es posible correr un programa Java sobre cualquier plataforma que lo habilite aún sin recompilar
ese programa. El lenguaje Java esta completamente especificadoy, por definicibn, una plataforma
con Java habilitado debe soportar un grupo conocido de librerías principales. Una
de esas librerías
es JDBC, la cual se puede pensar comouna versi6n Java deODBC, y es por sí misma un estandar
en crecimiento. Los vendedores de basesde datos se estan ocupando de crear puentes de JDBC
a sus sistemas particulares. JavaSoft tambien provee un driver de puente que comunica a JDBC
conODBC,permitiendo la comunicaci6nconbases de datospropietariasquenocuentancon
drivers nativosJDBC. El uso de Java en conjuncibn conJDBC proporciona una verdadera soluci6n
portable al escribir aplicaciones de bases
de datos.
Java, siendo robusto, seguro, facil de usar, fhcil de entender, y automaticamente descargable en
una red, es un excelente lenguaje para las aplicaciones de bases de datos.
Senecesitabauna
forma de que las aplicaciones Java se comunicaran
con las distintas bases de datos existentes.
JDBC es el mecanismo para hacerlo.
JDBC extiende las capacidades de Java. Por ejemplo, con Java
y la API de JDBC, es posible
publicar una pagina Web que contenga un applet que use informaci6n obtenida de una base de
datos remota. O una empresa que use JDBC para conectar a todos sus empleados (aún si ellos
usan un conglomerado de sistemas Windows, Macintosh y UNIX) a una o mas bases de datos
internas por mediode una intranet.
Qué es lo que hace JDBC
De forma simple, JDBChace posible tres cosas:
establecer una conexi6n con una base de datos, que puede ser remota o no.
enviar instrucciones SQL a la base de datos.
procesar los resultados obtenidos de la base de datos.
El siguiente fragmento de cddigo da un ejemplo besico
de estos tres pasos:
Connection con = DriverManager.getConnection(
"jdbc:odbc:base", "login", "password")
;
Statement stmt = con.createStatement0;
Resultset rs = stmt .executeQuery ("SELECTb, a,
c FROM Tabla");
while (rs.next0) {
int x = rs.getInt ("a");
String S = rs.getString("b");
float f = rs.getFloat ("c");
}
JDBC es una API de bajo nivel y es la base de APls de alto nivel
JDBC es una interfaz de "nivel bajo",
lo que quiere decir que es usada para invocar
(o llamar)
comandos SQL directamente. Trabaja muy bien en este aspecto y es m& facil de usar que otras
APls de conectividad a bases de datos, pero fue disefiada tambien para ser la base sobre la cual
a7
construir interfaces de alto nivel y herramientas. Una interfaz de alto nivel es "amigable al usuario",
y utiliza una API mas entendible o conveniente la cual se traduce detras del escenario en una
interfaz de nivel bajo tal como JDBC. AI tiempo de escribir esto, se encuentran en desarrollo dos
APls de alto nivel basadas en JDBC:
1. UnSQLintegradoparaJava.LosDBMS'simplementanSQL,unlenguajedisefiado
especificamente para usarse con bases de datos. JDBC requiere que las sentencias
de
SQL se pasen como cadenas a los metodos de Java. Un preprocesador integrado de SQL
permitire al programador mezclar sentencias
SQL directamente con Java: por ejemplo, una
variable Java puede usarse en una sentencia SQL para recibir o proporcionar valores de
SQL. El preprocesador integrado de SQL traslada luego esta mezcla de Java/SQL a Java
con llamadas de JDBC.
2. Un mapeo directo de tablas de una base de datos relaciona1 a clases de Java. JavaSoft y
otros tienen planes de llevar a cabo esto. En 6ste mapeo "Objeto/Relacibn", cada línea de
una tabla viene a ser una instancia de la clase, y cada valor de columna corresponde aun
atributo de esa instancia. Los programadores pueden entonces operar directamente con
objetos de Java; las llamadas SQL requeridas para extraer y almacenar datos se generan
automaticamente "bajo la cubierta." Tambi6n se proporcionan mapeos mas sofisticados,
por ejemplo, cuando renglones de tablas múltiples se combinan en una clase de Java.
Como el inter& en JDBC ha crecido, mas desarrolladores trabajan con herramientas basadas en
JDBC para construir programas mas facilmente. Los programadores tambi6n escriben aplicaciones
que hacen el acceso a las bases de datos mas sencillo para el usuario final. Por ejemplo, una
aplicaci6n puede presentar un menú de tareas de bases de datos de las cuales escoger. Despues
de que una tarea es seleccionada, la aplicacidn presenta los cuadros de texto para llenarlos con la
informaci6nnecesariaparallevaracabolatareaseleccionada.Conlaentradarequerida
ya
ingresada, la aplicaci6n entonces invoca autometicamente los comandos SQL necesarios. Con la
ayuda de una aplicaci6n como 6sta, los usuarios pueden hacer operaciones con bases de datos
aún cuando tengan pocoo ningún conocimiento de la sintaxis de SQL.
9.2 JDBC versus ODBC y otras APls
En &te punto, la API de ODBC (Open Database Connectivity) de Microsoft es probablemente la
interfaz de programaci6n de aplicaciones
mas ampliamente usada parael acceso a bases de datos
relacionales. Esta ofrece la habilidad de conectarse a casi todas las bases de datos en casi todas
las plataformas. Nos preguntaremos que significado tiene entonces JDBC si ya existe una interfaz
popular que supuestamente hace lo mismo, es decir, porque simplemente no usar ODBC desde
Java?
La respuesta es que si se puede usar ODBC desde Java, pero es mejor con la ayuda de JDBC en
la forma de un driver puente JDBC-ODBC. Estos drivers traducen las llamadas de JDBC a ODBC
permitiendo comunicarse con bases de datos propietarias que no tienen
ni idea de que existe Java.
De esta manera por ejemplo podemos trabajar con una base de datos Access de Microsoft que usa
ODBC, con el lenguaje Java. La pregunta ahora viene a ser, "Porquk es necesario JDBC?" Hay
varias respuestas a 6sta pregunta:
1. ODBC no es apropiado para usarse directamente con Java porque utiliza una interfaz tipo
C.LasllamadasdesdeJavaac6digo
C tienenvariasdesventajasenlaseguridad,la
puesta en prhctica, robustez, y en la portabilidad autometica de las aplicaciones.
88
2. Unatraduccidn literal de la ODBC C API aunaJavaAPIpodríanoserdeseable.Por
ejemplo, Java no tiene apuntadores, y ODBC hace un copioso uso de ellos, incluyendo el
notoriamente propenso a error apuntador generico "void
*". Se puede pensar en JDBC
como un ODBC traducido a una interfaz orientada a objeto que es mas natural para los
programadores de Java.
3. ODBC es difícil de aprender. Este combina caracteristicas simples y avanzadas,
y tiene
opciones complejas aún para consultas simples. JDBC, por otro lado, fue disenado para
mantenersimple lo simplemientraspermitecapacidades
mas avanzadascuandoes
necesario.
4. UnaJavaAPIcomo JDBC esviabledeformaquesepuedaobtener
una soluci6ncon
"Java puro". Cuando se usa
ODBC, el ODBC driver manager y los drivers se deben instalar
manualmente
en
cada
mequina
cliente.
Como
el driver
de
JDBC esta
escrito
completamente en Java,el cddigo JDBC es automaticamente instalable, portable, y seguro
en todas las plataformas Java desde computadoras
de red hasta mainframes.
En resumen, la JDBC API es una interfaz Java natural paralos conceptos y abstracciones basicas
del SQL. Esta construida sobrelos principios usados paraODBC, de forma que los programadores
familiarizados
con
ODBC
encontraran
muy facil de aprender
JDBC.
JDBC
retiene
las
caracteristicasbasicas de diseiio deODBC; de hecho,ambasinterfacesestanbasadasen
la
NOpen SQL CLI (Call Level Interface). La gran diferencia es que JDBC se estructura
y refuerza
sobre el estilo y virtudes de Java,y, por supuesto, es facil de usar.
Recientemente, Microsoft ha introducido nuevas APls mas alla de ODBC: RDO, ADO, y OLE DB.
Estos diseiios se mueven en la misma direcci6n que JDBC de muchas maneras, esto es, en ser
una interfaz de base de datos orientada a objetos basadaen clases que puede ser implementada
sobre ODBC. Sin embargo, no se ha visto funcionalidad que imponga a algunade 6stas interfaces
comounaalternativaaODBC,especialmenteconunmercadodedrivers
de ODBCbien
establecido. La mayoría de ellos representan un fino disfraz para ODBC. No se esta diciendo que
JDBC no necesite evolucionarde su liberacidn inicial; sin embargo, posiblementela mayoría de las
nuevas funcionalidades radicaran enAPls de alto nivel tales como los mapeos objetolentidad y el
SQL integrado mencionados antes.
9.3 La arquitectura de JDBC
Como se 'mencion6 anteriormente, JDBC es una API de bajo nivel y es la base para APls de alto
nivel: los desarrolladoresusaranlasclaseseinterfaces
de la APIdeJDBCparahacerlas
transaccionesnecesariascon el DBMS, mientras el fabricante de driversutiliza el JDBCpara
modelarlos de acuerdo a &te.
dos capas
principales:
la API de JDBC
que
soporta
las
En detalle JDBC consiste
de
comunicaciones entre la aplicaci6n y el Administrador de JDBC; y la API del JDBC Driver que
soporta las comunicaciones entreel Administrador de JDBC y el driver. El Administrador maneja la
comunicaci6n con múltiples drivers de diferentes tipos, desde interfaces directas
enJavahasta
drivers de red y drivers basados en ODBC. Ver
la Figura 8.
89
t
..........................................................................
JDBC A P I
parte de JDBC
(paquete:java.sql.*)
.................................
.........................................
JDBC Driver A P I
Figura 8. Arquitectura de JDBC.
Acceso de la API JDBC a las bases de datos
La API de JDBC soporta dos modelos distintos de acceso a las bases de datos:
0
0
Modelodedoscapas(two-tier).
Modelodetrescapas(three-tier).
Modelo de dos capas (two-tier)
En el modelo de dos capas (Figura 9), un applet de Java o aplicacibn interactúa directamente con
la base de datos. Esto requiere de un driver de JDBC que se pueda comunicar con el sistema
manejador de la base de datos en particular que esta siendo accesada. Este driver estara instalado
en el sistema local. Las sentencias de SQL de los usuarios son entregadas a la base de datos, y
los resultados de esas sentencias son enviados de regreso al usuario. La base de datos puede
localizarse en otra mequina a la cual el usuario se conecta vía una red. Esto se conoce como una
configuración Cliente/Servidor, con la mequina del usuario como el cliente,y la maquina que tiene
la base de datos comoel servidor. El programa cliente envia instrucciones SQL a la base de datos,
y esta las procesa y envía los resultados de vuelta al usuario. La red puede ser una intranet, la
cual, por ejemplo, conecta alos empleados de una corporación,o bien puede ser la Internet.
90
1 - I1
I
Aplicación Java
Máquina Cliente
1
DBMS-protocolo
propietario
1-
Servidordebasededatos
Figura 9. Modelo de dos capas,
Modelo de tres capas (three-tier)
En el modelo de tres capas (Figura IO)
los
, comandos son enviados a un "middle tier"
o capa
intermedia de servicios, el cual luego envía las sentencias SQL a la base de datos. La base de
datos procesa las sentencias SQL y envía los resultados de vuelta a la capa intermedia, quien
despues los envía al usuario. El modelo de tres capas resulta muy atractivo ya que la parte media
o middle tier hace posible mantenerun control sobre los accesos y los tipos de operaciones que se
pueden hacer en la base de datos. Otra ventaja de la existencia del middle tier es que el usuario
puede emplear una API de alto nivel de uso fdcil que es trasladada por la capa intermedia en las
llamadas de bajo nivel apropiadas. Finalmente, en muchos casos la arquitectura
de trescapas
puede proporcionar ventajas de rendimiento,ya que los drivers JDBC para conectarse con la base
de datos, nohan de residir enla maquina cliente.
Mtiquina Cliente
HTML browser
Llamadas aHTTP, Rh41, CORBA
Servidor de
Adicaci6n
(Java)
I
L
~
kServidor
~
~
i
~
~
DBMS-protocolo propietario
DBMS
I
Servidorbase
de
datos
de
I
Figura I O . Modelo de trescapas.
Hasta ahora el middle tier se ha escrito típicamente en lenguajes como C o C++, que ofrecen un
alto rendimiento. Sin embargo, con la introducci6n de compiladores de optimizaci6n que traducen
el cddigo compilado Java en c6digo de maquina específico
y eficiente, se esta volviendo practico
el
implementar la capa intermediaen Java. Esto es una gran adicibn, haciendo posible tomar ventaja
de la robustez de Java, los multihilos de ejecucibn, y las características de seguridad. JDBC es
importante para permitirel acceso a basesde datos desdeun middle tier Java.
10
Conexión JDBC a bases de datos
En Bste capítulo conoceremos las clases del paquete
javasql. Estudiaremos las clases mínimas
y
para realizar una aplicacidn Java que sea capaz de conectarse a una base de datos existente
realizar la gestidn de la misma. Se veran a su vez los metodos
mas importantes de dstas clases
que intervienen directamente en la conexidn con una fuente de datos y la ejecucidn de sentencias
de SQL. La aplicacidn se desarrollara y probara en este mismo capítulo usando las herramientas
del Java DevelopmentKit (JDK) proporcionado en forma gratuita por Sun Microsystems.
10,l Las clases del paquete java.sql
AI igual que como sucedid con ODBC, la API de
JDBC contiene un grupo de clases para el trabajo
de conexidn a la fuente de datos, otro grupo para la ejecucidn de comandos, otro para obtener
características de drivers y del conjunto de resultados, y clases para el manejo de errores. Todas
&stas clases estan contenidas en
el paquete java.sg/ dentro del archivoc/asses.zipen del directorio
lib de jdk.
Como es común en Java, no todas las clases de un paquete se utilizan igual, pues algunas son
interfaces, otras son objetos y el resto son excepciones para
el manejo de errores, y la API de
JDBC no es diferente respecto a esto. La API de JDBC para la versidn de JDK 1.1.6 (al tiempo de
escribir esto Sun anunciaba la versidn 2.0 de JDBC que viene con el JDK 1.2) cuenta con un total
de ocho interfaces, seis objetos y tres excepciones documentadas el
enpaquete. Como el tema de
Bste trabajo no es Java ensí sino JDBC, no se profundizara en cuanto alos conceptos de Interfaz,
Objeto y Excepcidn de Java, tampoco se hablara de los modificadores
public, private, abstract y
otros.Seentiendeque
el lectortienenocionessobreesto.
A continuacidn sehaceunabreve
descripcidn de las clases de la API de JDBC.
91
92
Interfaces de JDBC
El paquete javasql proporciona varias interfaces para lograr la conexidn con la base de datos
y
ejecutarsentenciasdeSQL.ConlasinterfacesdelaAPIdeJDBCsepuedenejecutar
instrucciones normales de SQL, instrucciones dinarnicas deSQL y procedimientos almacenados o
storedprocedures. Las interfaces deJDBC son las siguientes:
CallableStaternent
La interfaz CallableStaternent proporciona metodos para llamar
stored procedures que regresan
valores de salida. El objeto CallableStaternent hereda el objeto Preparedstatement, pero a su vez
agrega metodos para registrar parametros para que sean parametros de salida
y proporciona otros
metodos para quelos parametros sean devueltos desde el procedimiento almacenado.
Connection
La interfaz Connection es el objeto que proporciona a la aplicacidn Java una conexidn a la base de
datos. Este objeto puede emplearse para crear todos los distintos objetos Statement para ejecutar
instrucciones de SQL y procedimientos almacenados. Tambikn permite establecer las propiedades
de transaccidn para la conexidn.
DatabaseMetaData
La interfaz DatabaseMetaData proporciona diversos metodos para obtener informacidn sobre la
base de datos. La interfaz proporciona mktodos para obtener el listado de las tablas de una base
de datos especifica,asi como las llaves primarias, las columnasy otros varios tipos de informacidn
para las tablas especificadas.
Driver
El objeto de la interfazDriver es un objetoDriver para una base de datos especifica proporcionado
por el distribuidor de JDBC. Contiene informacidn específica sobre
la conexidn de la aplicacidn
Java.Proporcionatambieninformacidnsobrelabasededatos(porejemplo,informacidndela
version).
Preparedstatement
La interfaz PreparedStatement permite ejecutar instrucciones dinarnicasde SQL y procedimientos
almacenados. Las instrucciones dinarnicas de SQL difieren de las instrucciones normales de SQL
porque en las instrucciones dinarnicas no se conocen
los valores al momento de la creacidn. La
interfazpermiteestablecer los diversosparametrosdeinstruccionesdinarnicasconvaloresde
datos especificados.
Resultset
Lainterfaz Resultset es el objetoquesecrea
y se utilizaparaobtenerinformacidndeuna
instruccidnSelectde
SQL. Estainstruccidnretornauncursorqueesutilizadoporlainterfaz
Resultset para navegar a traves delos resultados retornados por la instruccidn Select. Proporciona
varios metodos para obtener informacidn de las diferentes columnas contenidas en el cursor.
93
ResultSetMetaData
La interfaz ResultSetMetaDafa permiteobtenerinformacidnsobreunconjuntoderesultados
retornado. El objeto ResultSetMetaData secreaapartirdeunobjeto
ResultSet yproporciona
informacidn especlfica a ese objeto. Permite obtener, de un conjunto de resultados, el número de
columnas, los nombresytiposde
las columnas, y otrainformacidnpertenecientealobjeto
ResultSet retornado.
Statement
La interfaz Statement secreaapartirdelobjeto
Connection y se puedeusarparaejecutar
instrucciones SQL estandar y procedimientos almacenados. El objeto proporciona dos metodos
principales: executeQuery() y executeUpdate(). Estos metodos permiten ejecutar consultas de SQL
y actualizaciones de SQL. El rnetodo executeQuery() retornara un objeto ResultSet. Este objeto es
el ancestro para las interfacesPreparedStatementy CallableStatement.
Objetos de JDBC
El paquete java.sq/ tambien proporciona algunos objetos que pueden usarse en las aplicaciones
Java. La mayoría de los objetos se emplean para proporcionar a Java algunos de
los tipos de
datos específicos para base de datos disponibles en la mayoría de las bases de datos. Los objetos
de la API de JDBC se enlistan enseguida:
Date
El objeto Date puede aceptar valores de tipoDate de base de datos, es heredadodel objeto Date
normal de Java, pero proporciona metodos para accesar
los distintos valores dentro del objeto
Date.
DriverManager
El objeto DriverManager proporciona otra forma de realizar una conexidn a la base de datos.
El
objeto se usa principalmente para administrar objetosDriver de JDBC y puede utilizarse para crear
una conexidn a la base de datos. Proporciona varios metodos para
el registro de controladores,
obtencidn de conexiones y envío de informacidn
al flujo de salida de la base de datos.
DríverPropertylnfo
El objeto DriverPropedylnfo esutilizadoprincipalmentepor
los programadoresavanzadospara
manejar propiedades específicas de un objeto
Driver. Sdlo deben emplearlo los desarrolladores
que esten familiarizados conel funcionamiento de controladores de bases de datos.
Time
El objeto Time es heredado del objeto Date de Java. Proporciona varios metodos para obtener y
asignar valores del objeto. Se puede emplear para obtener valores de datos Time de la base de
datos.
94
Timestamp
El objeto Timestamp puede utilizarse para obtener valores de datos de la base de datos que son
deltipo Timestamp. El objetoproporcionavariosmetodosparacomparar
los valores de dos
diferentes objetosTimestamp.
TY Pes
El objeto Types contiene una lista de valores enteros predefinidos que identifican cada uno de los
diferentes tipos de datos disponibles para uso en aplicaciones JDBC. Los valores se utilizan
en
diferentes mktodos de la API de JDBC para especificar o identificar los tipos de valores de datos
particulares.
Excepciones de JDBC
CuandoocurreunerrorenJava,selanzaunaexcepci6n.Cualquierexcepci6nquelancen
los
metodosJavadebeser"atrapada"por
el usuario.LaAPIdeJDBCcontienetresnuevas
excepciones que pueden atraparse identificando varios errores enla ejecuci6n de metodos JDBC.
A continuaci6n se enumeran las
tres excepciones deJBDC:
DataTruncation
La excepci6n DafaTruncation se lanzasiempreque JDBC trunca un valordedatosenforma
inesperada. La excepción proporciona metodos para obtener informaci6n sobre
el valor de datos
que fue truncado así como para obtener informacibn sobre
el error de truncamiento.
SQLException
Laexcepcidn SQLException eslanzadapor casi todos los metodosen la APIdeJDBC.Esta
excepci6n proporciona varios metodos para obtener informaci6n sobre el error y el estado actual
de la transaccidn SQL.
SQLWarning
Laexcepcidn SQLWarning se generacuando la basededatosemiteunaadvertencia.La
advertencia se envia silenciosamente al objeto que la caus6.
10.2 Conexión con la base de datos
Existen dos formas de lograr conectarseuna
a base de datos. Una forma es
con la interfazDriver y
la otra escon el objeto DriverManager de JDBC. Para este efecto utilizaremos la base de datos de
Access de los ejemplos de ODBC, cuyo nombreDSN es coneccion. Veamos en primer lugar como
lo hace la interfaz Driver y despues veremoslo propio conel objeto DriverManager.
95
La interfaz Driver
La interfaz Driver ofrece varios metodos para obtener informaci6n sobre
el controlador actual de la
base de datos, entre ellos el metodo connect(), con el que se crea un objeto Connection que se
puede usar para accesar a la base de datos. La interfaz Driver proporciona
los metodos siguientes:
Tabla 25. Métodos de la interfaz Driver.
Método
Descripci6n
acceptsURLRegresaunvalorbooleanoqueindicasieldriverpuedeconectarseal
especificado.
connect
URL
Crea una conexión a la base de datos y regresa un objeto Connection para usarse
en la aplicación.
getMajorVersion
Obtiene
la
versión
mayor
(más
siginficativa)
del controlador.
getMinorVersion
Obtiene
la
versión
menor
(menos
significativa)
del
controlador.
getPropertylnfoDetermina
las propiedadesbaserequeridaspor
usando el controlador actual.
el usuarioparacrearunaconexión
jdbcCompliant
Regresa un valor booleano que indicasi el objeto Driver actual es compatible con
JDBC.
De los anteriores metodossdlo nos ocuparemos deacceptsURL y connect.
acceptsURL()
El metodo acceptsURL de la interfaz Driver tiene la misibn de averiguar si el objeto Driver actual
puede hacer una conexi6n en el URL especificado. El metodo toma un parametro de tipo String
que contiene el URL de la base de datos con la que se desea establecerla conexi6n. Si el objeto
Driver puede realizar una conexibn exitosa con el URL especificado el metodo regresara un valor
verdadero, de lo contrario regresara un valor falso. Si no se conoce sobre URLs vease la secci6n
dedicada a URLs dentro de este apartado.
connect()
El metodo connect permitecrearunaconexidnfísicaalabasededatosdesignadapor
un
parametro de tipo String. El metodo toma dos parametros. El primer parametro especifica el URL
de la base de datos en forma de un objeto String y puede ser cualquier base de datos que
el driver
actualsoporte.
El segundoparametroes
un objeto Properties que contiene la informaci6n
necesaria para conectarse ala base de datos, normalmenteel nombre de usuarioy la contrasena,
pero puede contener otros elementos.
Conexión con la interfaz Driver
El Listado 10 ejemplifica el uso de los metodos acceptsURL y connect de la interfaz Driver para
lograr la conexibn con la base de datos. Primero se determina si el URL es adecuado para una
conexi6n de base de datos,
y de serlo, se establece la conexi6n.
96
Listado I O . Conexi6n a una fuente de datos con
la interfaz Driver.
import java.util.*;
import java.sql.*;
public class Conexion {
public Conexion ( ) I
try (
/ / Cargamos el driverde puente jdbc-odbc
String drivername= "sun.jdbc.odbc.JdbcOdbcDriver";
Driver driver= (Driver) Class. forName (drivername) .newInstance
(1 ;
/ / Determinamos si el URL es válido
String url = "jdbc:odbc:coneccion";
if (driver.acceptsURL (url)
) I
/ / El URL es válido, conectamos a la BD
System.
out
.println("URL válido");
/ / Introducimos usuarioy contraseña
Properties p= new Propertieso;
p.put
("user","kuno");
p.put
("password",
"kodachi")
;
/ / Efectuamos la conexión a laBD
Connection c= driver.connect (ur1,p)
;
System.out.println("Conexión realizada ...") ;
1
else {
/ / El URL no es válido
System.out .println
("URL NO válido");
1
1
catch (SQLException e) {
System. out
.println("Error de JDBC . . . " + e .getMessage
() ) ;
1
catch (Exception e) {
System.out.println("Error . . . " + e.getMessage0 ) ;
1
1
public static voidmain (String args[])
Conexion app= new Conexion();
I
{
)
El driver de JDBC usado en el ejemplo es un puente JDBC-ODBC, por lo que el subprotocolo en el
URL es odbc. El driver es cargado con el método forName de la clase genérica Class y al mismo
tiempo es convertido en un objeto Driver e instanciado dentro de una variable para poder invocar
sus métodos acceptsURL y connect. Si el URL es valido, se crea un objeto Properties y se pasa
como parametrojunto con el URL al metodo connect para efectuarla conexibn.
El objeto DriverManager
El objeto DriverManager se usa como administrador de objetos
Driver; para ello se sirve de la
propiedad jdkdrivers del sistema en el objeto System. Con esta propiedad podemos especificar
distintos controladores JDBC para diferentes aplicaciones.Se pueden accesar las propiedades del
sistema mediante el método getProperties() del objeto System. Después de haber modificado el
valorde la propiedad jdbc.drivers, se pueden asignar las propiedades
del sistema utilizando el
mktodo setProperties. EnlaTabla 26 se enlistan los mktodos del objetoDriverManager y sus
descripciones:
riDci6n
97
Tabla 26. M6todos del objetoDriverManager.
Método
deregisterDriver
Elimina un objeto
Driver
de
getConnection
Crea
una
conexión
la lista de
controladores.
a base
la de
datos.
getDriver
Localiza objeto
un
getDrivers
Regresa un arreglo que contienetodos los objetos Driver actualmente registrados
con el administrador.
getLoginTimeoutRegresa
el número de segundosqueesperará
conexión.
getLogStream
Regresa
el flujo de Registro/Rastreo (loggin/tracingstream)
que
usará
administrador paralos objetos Driver.
println
Envía la cadena especificada al flujo actual de registro.
registerDriver
Registra con el adminstrador el objeto Driver especificado.
setLoginTimeoutAsigna
el númeromáximodesegundosqueesperará
establecer la conexión.
setLogStream
Establece
Driver que
conectará
al URL
especificado.
un controladorparaestableceruna
el
el controlador para
el flujo de Registro/Rastreo
que usarán los objetos Driver.
El metodo que ahora nos interesa esel m6todo getconnection.
getconnection
El método getconnection del objeto DriverManager tiene tres variantes distintas en cuanto a los
parámetros que acepta, pero todas ellas crean una conexi6n a la base de datos y regresan un
objeto Connection.
La primera forma de getconnection s610 toma el URL para la base de datos e intenta la conexi6n
con esta usando el objeto Driver actual o un objeto Driver adecuado de la lista de objetos Driver
registrados.En6stavarianteseasumequenoserequierenombre
de usuario,contrasena ni
ninguna otra propiedad de
base de datos para establecerla conexi6n.
La segunda forma de getconnection toma el URL para la base de datos, pero tambien toma un
objeto Properties que contiene varias propiedades requeridas para conectarse a la base de datos.
El segundo parametro debe ser un objeto Properties que contenga los elementos necesarios para
hacer una conexidn a la base de datos especificada.
La última variante de getconnection toma, como las dos anteriores, el URL de la base de datos,
peroenlugar de tomarunobjeto Properties, setomandosobjetos
String. Laprimeracadena
el nombre de usuario
identifica el nombre de usuario y la segunda contiene la contrasena para
dado.
Conexión conel objeto DriverManager
El ejemplo mostrado en el Listado 11 ilustra la forma en que se hace la conexih a la base de
datos coneccion usando el objeto DriverManager. Se utiliza la tercervariantedelm6todo
getconnection usando las mismas propiedadesde usuario y contrasena del ejemplo anterior:
98
Listado 11. Conexión a una fuente de datos con el objeto DriverManager.
import java.util.*;
import java.sql.*;
public class Conexion2 (
public Conexion2 ( ) {
try I
String drivername= "sun.jdbc.odbc.JdbcOdbcDriver";
/ / Registra el driver jdbc-odbcen las propiedades del sistema
Properties system = System.getProperties0;
system.put ("jdbc.drivers",drivername);
System.setProperties(system);
/ / Cadenas de URL, usuario y contraseña
String url = "jdbc:odbc:coneccion";
String usr= "kuno";
String psw = "kodachi";
/ / Realiza la conexión
Connection c = DriverManager.getConnection(ur1, usr, psw);
System.out.println("Conexi6n realizada . . . ") ;
}
catch (SQLException e) (
System. out
.println("Error de JDBC . . . " + e.getMessage ( )
1
catch (Exception e) {
System. out. println ("Error
. . . " + e.getMessage ( ) ) ;
) ;
)
1
public static void main (String args[])
(
Conexion2 app = new Conexion20;
}
}
Igual que antes, se utiliza un puente JDBC-ODBC. Este controlador se
registra en la propiedad
jdkdrivers del sistema. Posteriormente se crean las cadenas del URL, el usuario y la contraseiia,
lascualessepasancomoparametrosen
la tercervariante del metodogetConnection.Sin
embargo, bien pudo usarse la primer forma, la que s6lo requiere del URL, puesto que algunas de
las bases de datos de Access no precisan de usuario y contraseiia para ser accesadas desde la
máquina local. Este esel caso de la base de datoscunecciun.
Sobre los URLs de JDBC
URLson
las siglas para Uniform Resource Locator (LocalizadorUniformedeRecursos)
y
proporciona la informaci6n para localizar recursos en la Internet. Ejemplos típicos de URLs son los
usados para acceder a paginas desde un browser, por ejemplo http://java.sun.com, es un ejemplo
de URL para el protocolo de hipertexto. La primera parte del URL especifica el protocolo que se
usaparaaccesarlainformaci6n
y siemprevaseguidodedospuntos
":". Algunosprotocolos
comunes son ftp, http y file. El resto del URL, todo lo que sigue a los dos puntos, da la informaci6n
de donde se localiza el recurso. Si el protocolo es file, el resto del URL es el path al archivo. Para
los protocolos ftp y http, el resto delURLidentifica al host y opcionalmente el pathhaciauna
página especifica. Por ejemploel URL:
http://java.sun.com
sólo especifica el host; y el URL:
http://java.sun.com/products/jdbc
identifica la pagina de JDBC de Sun.
99
Un URL de JDBC proporciona una forma de identificar una base de datos de forma que
el driver
adecuado la reconozcay establezca una conexidn con ella. La sintaxis para un URL de JDBC tiene
tres partes separadas por":" y se muestra enseguida:
jdbc:<subprotocolo>:<nombre>
Las tres partes se describen por separado:
1. jdbc-el protocolo. El protocolo en un URL de JDBC siempre es jdbc.
2. <subprotocolor"el nombre del driver o el nombre del mecanismo de conexi6n a la base
dedatos, el cual puedesersoportadoporuno
o mas drivers.Unbuenejemplode
subprotocolo es "odbc", el cual se reserva para URLs que especifican nombres de fuentes
de datos de tipo ODBC. Por ejemplo, para accesar una base de datos a traves de un
puente JDBC-ODBC, se podría usar el URL siguiente:
jdbc:odbc:base
En &te ejemplo, el subprotocolo es "odbc" y el nombre es "base", que es un nombre de
fuente de datos de ODBC.
3. enombrer-una maneradeidentificarlabasededatos.
El nombre
puede
variar
dependiendo del subprotocolo. El objetivo del nombre es el de proporcionar la suficiente
informaci6n para localizar la base de datos. En
el ejemplo anterior, "base" es suficiente
porque ODBC se encarga de dar el resto de la informaci6n requerida. Una base de datos
en un servidor remoto requiere de mas informaci6n. Si la base de datos es accesada por
Internet, por ejemplo, la direcci6n de red debe incluirse como parte del nombre y debe
seguir la nomenclatura URL estandar:
//nombrehost:puerto/subnombre
El subprotocolo odbc es un caso especial. Se reserva para URLs con nombres de fuentes de datos
detipoODBC
y tienecomocaracterísticadistintiva
el permitircualquiernúmerodeatributos
despues del nombre (nombre de fuente de datos). La sintaxis completa para el subprotocolo odbc
es la siguiente:
Un ejemplo de un URL valido con subprotocolo odbc es:
jdbc:odbc:base;UID=ryoga;PWD=p-chan
10.3 Creación y ejecución de sentencias deSQL
Al hacer la conexión con la base de datos, ya sea usando
el objeto Driver o usando el objeto
DriverManager,secreaunobjetoConnection.ConelobjetoConnectionpodemosobtenerun
objeto Statement para la ejecucibn de sentencias deSQL, y para obtener los resultados. Ambos, el
objeto Connection y el objeto Statement, son interfaces de Java, con Bstas interfaces podemos
crear y ejecutar instrucciones SQL y tambien obtener los resultados. Se vera un ejemplo de c6mo
se puede lograr esto, pero antes estudiemos
los elementos necesarios paratal prop6sito.
1O0
La interfaz Connection
La interfaz Connection nos permitehacervariasoperacionescon
la basededatos y obtener
informaci6n de esta, ofrece varios metodos para el manejo de transacciones y de procedimientos
almacenados. Proporciona tambien algunos metodos para el manejo de errores. Pero uno de los
metodos mas útiles de la interfaz Connection es el que nos proporciona un objeto Statement, el
metodo createStatement. Otro metodo importante de la interfaz Connection es el metodo close,
con el cual se cierra la conexi6n con la basede datos. Los metodos que utilizaremosde la interfaz
Connection son:
close
El método close cierra explícitamente la conexi6n a la base de datos. La conexi6n se cierra de
todas formas al terminar la aplicacibn. Este metodo es útil cuando se tiene un número limitado de
conexiones disponibles a la base de datos. Con el metodo close se puede terminar una conexibn
despues de uncierto periodo de inactividad.
createstatement
El metodo createstatement crea un objeto Statement y lo regresa como valor. El objeto Statement
se usa para ejecutar sentenciasde SQL y obtener resultados.Se utiliza para ejecutar instrucciones
SQL estaticas. Para las instrucciones SQL dinarnicas o procedimientos almacenados se usan los
objetos Preparedstatementy CallableStatement.
La interfaz Statement
Seha vistoque el objeto Connection nossirveparaconectarnosaunabase
de datos.Para
Statement. El
ejecutarinstruccionesde SQL y obtener los resultadosdebemosusarunobjeto
objeto Statement, de igual manera que el objeto Connection, no puede crearse en forma directa.
Para crearun objeto Statement se asigna el valor de regreso de un metodo de otro objeto,
el objeto
Connection. El metodo createstatement del objeto Connection devuelve un objetoStatement como
valor.
Se puede usar un objeto Statement para ejecutar instrucciones SQL estaticas y obtener de vuelta
resultados de consultas SQL. Una instrucci6n SQL estdtica no toma ningún argumento para estar
completa. Una instruccidn dinarnica, en cambio, no esta completa hasta que se pasa cierto número
select,delete,
de argumentosa la instrucci6nSQL.Instrucciones
SQL estaticaspuedenser
update, insert e incluso un procedimiento almacenado. Las instruccionesupdate, delete e insert no
regresan ningún resultado;estos procedimientos simplemente actualizan datos en la base de datos
y no regresan nadade ella. Un procedimiento almacenado puede llevar a cabo cualquier operaci6n
de actualizaci6n de datos y puede tambien regresar una selecci6n de resultados de la base de
datos. Los métodosdel objeto Statement que nos interesanson:
close
El metodo close del objeto Statement libera de maneraexplícitalassentencias
y recursos
asociados al objeto Statement. Se liberan tanto los recursos usados porlos objetos del controlador
JDBC como los recursos que esten en uso en el servidor de base de datos. Tambien se usa el
método close para liberar cualquier bloqueo colocado a la base de datos por la ejecucidn de las
instrucciones de SQL.
101
executeQuery
El mdtodo executeQuery tiene como propdsito el envio de instrucciones select de SQL para la
obtencidn de los resultados que proporcionen. Los resultados se reciben en un objetoResultset. El
método executeQuery toma como parametro una instruccidn select de SQL
y regresa un objeto
Resultset que contiene los registros que coincidieron con
los criterios dela instruccidn select.
executeupdate
El método executeupdate se utiliza para ejecutar instrucciones SQL de actualizacidn tales como
delete, insert y update. El rnetodo toma como parametro una cadena que contiene la instruccidn
SQLde actualizacidn y regresa un entero que indica cuantos registros fueron afectados por la
instrucción SQL. Adicionalmente, se pueden ejecutar instrucciones DDL de SQL que no regresan
nada.
getResultSet
El mdtodogetResultSetseutilizaparaobtener
Statement y regresarlo como un objeto Resultset.
el conjuntoderesultadosactualdelobjeto
El objeto Resultset
El objeto Resultset es parecido a un arreglo bidimensional. Se compone de un número finito de
registros, o filas, y cada registro contiene un conjunto finitode columnas. Cada una de las casillas
formadas por las filasy columnas contienen datos, los cuales pueden ser de tipo cardcter, enteroo
nulo. LaFigura 11 muestraunarepresentacidnvisualdeunobjeto
Resultset. Lailustracidn
presentadatiene cinco registrosqueasu
vezcontienencincocolumnascadauno.Encada
los métodosdelobjeto
columnahayunaporcidndedatosquepuedeseraccesadamediante
Resultset.
Columnas
Figura 11. Representacion gráfica del objeto ResultSet.
AI obtener el objeto Resultset devueltadelabasededatostodavianopodemosver
los
resultados. Para visualizar los resultados que fueron regresados, debemos usarlos metodos next y
getXXX del objetoResultset. Estos metodos proveen la navegacidn a traves del objeto
Resultset y
el accesoavaloresdedatos
en dichoconjuntoderesultados,respectivamente.
Los metodos
getXXX dan una forma de obtener los valores de datos en el tipo de datos deseado, por ejemplo,
102
para obtener valores Float podemos usar el metodo getFloat para regresar una columna como un
objeto Float, para obtener una cadena se usa
el metodo getstring para regresaruna columna como
un objeto String y así sucesivamente. El metodo next mueve el cursor del objeto Resultset al
siguiente registro en el conjunto de resultados, aunque inicialmente el apuntador comienza en un
registro NULL que antecedeal primer registro real; por ello se debe
llamar al metodo next antes de
intentar accesar cualquiera de los datos contenidos en el conjunto de resultados. El metodo next
regresa un valor booleano que indicasi existe un registro en la posici6n de cursor actual. Si hay un
registrovididoen la posici6na la quesemueve el cursor, el metodoregresara true; encaso
contrario, regresara false.
Otro
objeto
interesante
es
la interfaz ResulfSetMefaData. Esta
interfaz
proporciona
datos
relevantes al conjunto de resultados, como por ejemplo,el numero de las columnas regresadasen
el objeto Resultset. Mas adelante se vera un poco mas sobre 6ste objeto.
Un ejemplo simple de ejecución de instrucciones de SQL
Con lo aprendido anteriormente estamos listos para crear nuestra aplicaci6n Java para ejecuci6n
de instrucciones SQL. Usaremos como antes
la base de datos de Access cuyo DSN esconeccion.
Construyamos nuestra aplicaci6n por pasos. Lo primero es, por supuesto, efectuar la conexi6n,
para ello usaremos la interfaz
DriverManager y cargaremos el driver JDBC-ODBC directamente
con el metodo forName de la clase genericaClass:
Class.
forName
( "sun.
jdbc.
odbc.
JdbcOdbcDriver")
;
String url= " jdbc: odbc: coneccion";
String uid= "tendo";
String psw = "nabiki";
Connection c = DriverManager.getConnectíon(ur1, uid, psw);
Como ya tenemos el objeto Connection, podemos entonces obtener, a partir de este, un objeto
Statement, con el metodo createStatemenf:
Statement stmt= c.createStatemento;
Con el objeto Statement recien creado, probaremos el crear una tabla t_prueba enlabasede
datos coneccion. Posteriormente insertaremos registrosen la tabla para despues leerlos mediante
una instruccih select de SQL. Estas operaciones son las mismas que se hicieron en
el ejemplo de
uso de las funcionesdel m6dulo de Visual Basic: Conexion.bas,del capítulo 8; las instrucciones de
SQL son las mismas:
//Se crea la tabla
de ejemplo
sql = "CREATE TABLE t-prueba ( " ;
sql += "id INTEGER CONSTRAINT constl PRIMARY
KEY,
sql += "dato1 TEXT ( 2 0 ) ,
sql += "dato2 TEXT(30)";
sql += " ) ;";
stmt
.executeupdate
( s q l );
'I;
'I;
//Se insertan dos registros:
sql = "INSERT INTO t-prueba VALUES (1, \'pruebal\', \'texto pruebal\');"
sql += "INSERT INTO t-prueba VALUES ( 2 , \'prueba2\', \'texto prueba2\');"
int val = stmt.executeUpdate(sq1);
//se realiza la consulta
sql = "SELECT * FROM t-prueba WHERE id = 1 ; "
ResultSet rs = stmt.executeQuery(sq1);
103
Nótese que se us6 el caracter de escape Y en las instrucciones insert de SQL. AI igual que Java,
SQL requiere que las constantes de cadena estdn contenidas en alguna forma de entrecomillado.
Se debe emplear el caracter de escape ( \ ) debido a que la mayoria de los controladores colocan
un ap6strofe ( ' ) antes y despuds de cada instruccidn
de SQL que envian a la base de datos.Si se
omiteelcaracterdeescapeantesdelacomillasencilla,entonces
el controladorJDBC
lo
interpretara comoel fin de un comando SQL a la base de datos.
Tenemos pues, en dste momento, el objeto ResultSef, que nos permitirh visualizar la informacibn
extraídaconlainstruccidn
select. Usaremos el mdtodo getstring delobjeto
Resultset que
convenientemente nos dara los datos como objetosString para su facil presentacidn:
//Obtenemos el número de columnas
ResultSetMetaData rsmd= rs.getMetaData0;
int cols = rsmd.getColumnCount();
//Se despliega la información
String registro = "";
while (rs.next( ) ) {
for (int i=l; i<=3; i++) registro += rs.getString(i)
System.out.println(registro);
+
"
";
A partir del objeto Resultset, creamos un objeto ResultSetMetaData con el mdtodo gefMetaData
delobjeto Resultset. El mdtodo getColumnCount delobjeto ResultSetMetaData devuelveel
número de columnas regresadas en el conjunto de resultados. Un objeto ResultSetMetaData nos
brinda informacidn variada sobre
un conjunto de resultados representado por
un objeto ResulfSet.
La parte final de nuestro programa es la limpieza y liberaci6n de recursos,
o sea, cerrar los objetos
ResultSet, Statement y Connection explícitamente en lugar de esperar que sean cerrados en forma
o al terminar la aplicacidn:
automatica por el colector de basura,
rs.close ( ) ;
stmt.
close
() ;
c.close ( ) ;
De dsta forma hemos finalizado nuestra pequefia aplicacidn Java que se conecta a una base de
y consultas. Los objetos de Java aquí presentadosde la API de JDBC
datos y hace actualizaciones
son los mínimos para hacer operaciones de bases de datos. El listado de cddigo completode dsta
aplicaci6n se muestra en el siguiente apartado. Tambidn se describen las herramientas de JDK
usadas para la compilacidny prueba de los applets.
10.4 Las herramientas deJDK
Hasta ahora, se han visto ejemplos de cddigo Java que ilustran algunas de las clases de la API de
JDBC. Pero no se ha explicado como es que se sabe que funcionan. Todos
los ejemplos de la
partedeJDBCdedstetrabajosecodificaronusandocualquiereditordetexto,
el NotePad de
Windows fue uno delos mas usados. Para compilarlos y correrlos se usaron las herramientas
javac
y java del Java Development Kit (JDK 1.1.6) respectivamente. Existen, sin embargo, herramientas
visuales para desarrollo con Java, por ejemplo el JBuilder y
el Developer Studio, dstas permiten
ciertodesarrollodetipoRAD(RapidApplicationDevelopment).
El autor sdlo seaboc6alas
herramientas de JDK que se describen
en este apartado.
104
javac-El compilador de Java
javac se utiliza para compilar programas Java.
SINTAXIS
javac [opciones] Archivo1.java Archivo2.java ... ArchivoN.java
El comando javac compila cbdigo fuente de Java a cbdigo objeto. Después de eso se puede usar
el intérprete deJava-el comando java-para interpretar el cbdigo objeto de Java.
ElcbdigofuentedeJavadebeestarcontenido
en archivoscuyosnombresfinalicenconla
extensión .java. El nombre
de
archivo
debe
coincidir
con
el nombre
de
la clase,
como
nombre-clase. j ava, si la clase es publicao es referenciada desde otro archivo fuente.
Para todas las clases definidasen cada archivo fuente compiladocon javac, el compilador guarda
los archivosobjetoresultantesen
un archivoclass,guardandolo con unnombredelaforma
nombre-clase.class. A menos que se especifique la opción -d, el compilador coloca los archivos
class en el mismo directoriodel archivo fuente.
Cuando se requieren de clases propias es necesario especificar la localizacibn de éstas. Para ello
seusa la opcibn -classpath o lavariabledeambiente
CLASSPATH. El classpathes una
secuencia de directorios (o archivos zip) en los que javac busca las clases no definidasen alguno
de los archivos especificados directamente como argumentos del comando. El compilador busca
en los directorios seAaladosel archivo objeto y el archivo fuente, recompilando el archivo fuente (y
regenerando el archivo objeto)si M e es mas reciente.
ALGUNAS OPCIONES
-classpath rutas
Especifica las rutas en las que javac buscara las clases necesarias o que son referenciadas por
las clases que se estan compilando. Tiene preferencia sobre el directorio default o la variable de
ambiente CLASSPATH. Las rutas se separan con punto y coma. Siempre es Útil que el directorio
que contiene los archivosfuenteeste en el classpath. Es buenoincluirsiemprelasclasesdel
sistema al final de las rutas.Por ejemplo:
...
javac -classpath .;C:\users\dac\classes;C:\tools\java\classes
-d directorio
Especifica el directorioraíz de la jerarquia dearchivosdeclases.Enotraspalabras,esto
esencialmente un directoriode destino para las clases compiladas. Por ejemplo,
el comando:
es
javac -d C:\users\dac\classes MiPrograma.java
causa que los archivos de clases para las clases contenidas en el programa MiPrograma.java se
guarden en el directorio C:\users\dac\classes. Si las clases estanen el paquete demosbwt, las clases
seren colocadas enel directorio C:\users\dac\classes\demosbwt.
Note que las opciones -d y elasspath tiene efectos independientes.El compilador s610 lee desde
el classpath, y sblo escribe en el directorio de destino. Siempre es útil que el directorio de destino
105
este en el classpath. Si no se especifica la opcidn -d, los archivos de clases son guardados en el
directorio actual como directorio raíz.
deprecation
Genera advertencias por el uso de clases
o metodosdiscontinuados.Unmetodo
o claseestá
discontinuado si en su documentacidn contiene la marca
@deprecated. El compilador emitir6 una
advertencia al final de la compilacidn aún
si la opcidn deprecation no es usada;estaopci6n
causa que se seflalenlos metodos o clases discontinuadas que se usaron.
-verbose
Causa que el compilador y el enlazador impriman mensajes sobre que archivos fuente se est6n
compilando y que archivos de clases se est6n cargando.
java-El
Intérprete de Java
java ejecuta una aplicacidn Java.
SINTAXIS
java [opciones] nombreclase <args>
El comando java ejecuta una aplicacidn Java. Esto mediante el inicio de un JRE (Java Runtime
Environment), la carga de la clase especificada, y la invocacidn del mbtodo main de la clase. El
comando java ejecuta archivos Java.class creados por el compilador de Java,
javac.
El argumento nombreclase es el nombre de la clase ha ser ejecutada.
paquete de procedenciaen el nombre, por ejemplo:
nombreclase debe incluir su
java java.lang.String
Cualesquieraargumentosqueseincluyanenlalíneadecomandodespu6sde
nombreclase se
pasarán al metodo main de la clase. La clase a ejecutar debe contener un m6todo
main definido
como sigue:
class Aclass {
public static
. . .
I
void
main(String
argv[l)
{
1
java ejecuta el metodo main y luego termina el programa a menos queel metodo main cree uno o
más hilos de ejecución. Si se crearon hilos de ejecucidnel comando java no termina hasta que el
último hilo termina.
Cuando se definen clases propias se necesita especificar su localizacidn. Se utiliza la variable de
ambiente CLASSPATH para ello. CLASSPATH consiste de una lista de directorios separados por
puntos y comas que especificanlas rutas. Por ejemplo:
.;C:\xyz\classes
106
ALGUNAS OPCIONES
-classpath rufas
Especifica las rutas en las que el comando java buscara las clases. Tiene preferencia sobre la
variable de ambiente CLASSPATH si esta es utilizada. Los directorios van separados por punto y
coma. Por ejemplo:
C:\xyz\classes;C:\usr\local\java\classes
-noasyncgc
Desactiva la recolecci6n de basura asincrona. Cuando se desactiva la recoleccibn de basura esta
no se lleva a cabo hasta que es explícitamente invocada o el programa sufre un desbordamiento
de memoria. Normalmente la recolecci6n de basura corre como un hilo de ejecucidn asíncrono en
paralelo con otroshilos.
-nojit
No invocar el compilador de c6digo objeto a c6digo maquina, Just
In Time. La maquina virtual
interpreta directamenteel c6digo objeto, sin convertirlo a c6digo maquina.
-version
Imprime informaci6n de laversih.
-help
Imprime un mensaje sobrela utilizaci6n.
-v, -verbose
Ocasiona que se imprima un mensaje sfdout
a
cada vez que un archivo de clase es cargado.
-verbosegc
Ocasiona que el recolector de basura imprima mensajes cuando este libera memoria.
Compilando y corriendo un ejemplo
El ejemplo que se usara en esta ocasi6n es el visto en el apartado anterior. En este ejemplo se
unen todos los elementos de JDBC revisados, pues se realiza una conexi6n de base de datos, se
actualiza una tabla y despues se hace una consulta y se presentan los resultados. Presentamos
pues, el listadocompletodelejemplodeejecuci6ndeinstruccionesde
SQL. Losmensajesde
salida a lo largo del programa son para llevar
un seguimiento del mismo:
Listado 12. Ejecución de instrucciones de SQL.
import java.sql.*;
import java.util.*;
public class EjecucionSQL {
public EjecucionSQLO {
try {
/ / S e carga el driver JDBC-ODBC
107
Class.forName("sun.jdbc.odbc.JdbcOdbcDriverlf);
System.out.println("Driver JDBC-ODBC cargado
//Se preparan las cadenas
de URL, usuario y contraseña
String url = "jdbc:odbc:coneccion";
String uid = "tendo";
String psw = "nabiki";
//Se realiza la conexión
y se crea un objeto
de sentencia
Connection c = DriverManager.getConnection(ur1, uid, psw);
System.out.println("Conexion realizada
;
Statement stmt= c.createStatemento;
//Se crea la tabla
de ejemplo
String sql = "CREATE TABLE t-prueba ( " ;
sql += "id INTEGER CONSTRAINT constl PRIMARY
KEY, ";
sql += "dato1 TEXT(20)
sql += "dato2 TEXT(30)
";
sql += " ) ;";
stmt .executeupdate (sql);
System.out.println("Tab1a de ejemplo creada
.. ;
//Se insertan dos registros:
sql = "INSERT INTOt-prueba VALUES (1,\ 'pruebal\ I , \ texto pruebal\)
int val = stmt.executeUpdate(sq1);
sql = "INSERT INTO t-prueba VALUES (2,\ 'prueba2\ ,\ texto prueba2\)
val = stmt.executeUpdate(sq1);
Systern.out.println("Registros agregados ala tabla . . . ") ;
//se realliza la consulta
sql = "SELECT * FROM t-prueba;";
Resultset rs = stmt.executeQuery(sq1);
System.out.println("Consu1tahecha. Resultados:");
//Obtenemos el número de columnas
ResultSetMetaData rsmd= rs.getMetaData();
int cols = rsmd.getColumnCount();
//Se despliega la información
while (rs.next ( ) ) {
String registro = " " ;
for (int i=l; i<=cols; i++) registro += rs.getString(i) + " ";
System.out.println(registro);
I
//Cerramos objetos y conexión
rs.close ( ) ;
stmt.close ( ) ;
c.
close
() ;
System.out.println ("Conexion cerrada
, ..
;
. . . ' I ) ;
. . . ' I )
, ' I ;
.'I)
;";
;'I;
'I)
I
catch (SQLException e) {
System.out.println("Error de SQL:
"
+ e.getMessage());
}
catch (Exception e) (
System.out.println
("Error:
" + e.getMessage ( )
) ;
I
public static voidmain (String argv[]) {
EjecucionSQL app= new EjecucionSQLO;
Para compilareste programa y generar la clase de Java usaremosel comando javac. Suponiendo
que tenemos el JDK instalado en el directorio C:\jdkl.l.G, y que nuestro archivo fuente estA en el
directorio C:\jdkl .I
.6\applets, simplemente haremos:
C:\>cd \jdkl.l.6\applets
C:\jdkl.l.G\applets>c:\jdkl.l.6\bin\javac EjecucionSQL.java
108
si en la variable de ambientePATH se agrega la ruta C:\jdkl. 1.6\bin, solamente bastarla escribir:
C:\jdkl.l.G\applets>javac EjecucionSQL.java
si no existeningúnerror,despues
de lacompilacióndelarchivofuentesehabragenerado
el
archivo objeto: EjecucionSQLdass. Para correr este programa usaremos el comando java como
sigue:
C:\jdkl.l.G\applets>java EjecucionSQL
es importante respetar las letras mayúsculas y minúsculas del nombre de la clase, pues como en
C, las variables y nombres de objetos se diferencian en el uso de mayúsculas y minúsculas; los
nombres EjecucionSQL y ejecucionsql representan objetos distintos para Java. Veamos ahora lo
que ocurre despues de ejecutar el programa:
C:\jdkl.l.G\applets>java EjecucionSQL
Driver JDBC-ODBC cargado. . .
Conexion realizada . . .
Tabla de ejemplo creada . . .
Registros agregados ala tabla . . .
Consulta hecha. Resultados:
1 pruebal texto pruebal
2 prueba2 texto prueba2
Conexion cerrada . . .
C:\jdkl.l.G\applets>
Vemos que el programa corrió con dxito, pues nose generaron excepcionesque fueran mostradas
entre los mensajes que se colocaron a propdsito. De la salida del programa observamos tambien
los dos registros regresados como resultado de la consulta a la tabla Lprueba. Esta tabla debera
o bienpuedeserunbuen
serborradaposteriormentede
la basededatosenformamanual,
ejercicio parael lector agregar el código necesario al programa EjecucionSQL para eliminar
la tabla
antes de cerrar la conexión.
1o9
Para más información
Para una mayorreferenciasobrelasclasesdelaAPIde
JDBC y susmktodos,consúltese
documentacidn deJDK, o bien se puede ir directamente
al sitio de JavaSoft:
la
http://iava.sun.com/products/idkll.2/docs/quide/idbc/index.html
A 6stas alturas ya debe haber sido liberada la versidn 2.0 de JDBC junto con el JDK 1.2, la cual
y mejorassobrelasexistentes.SunMicrosystems
seguramentepresentaráclasesnuevas
constantemente libera versiones mejoradas deJDK y JDBC. Para mantenerse al corriente con las
mismas se recomienda consultar con regularidad
el sitio de JavaSoft:
http://iava.sun.com
PARTE IV. Apéndices
O Declaración de las funciones dela API de ODBC
O Conexion.bas: Código de las funciones
A
Declaración de las funciones de la
API de ODBC.
Se muestra a continuacibn el contenido del archivo ODBC32.bas. En 61 se hace la importacibn de
las funciones de la libreria odbc32.dll para su uso en Visual Basic. Este archivo contiene tambikn
las constantes y tipos de datos usados porla mayoría de las funciones de
la API de ODBC.
Listado 13. Listado del módulo ODBC32.bas.
'Attribute VB-Name
#If Win32Then
=
"ODBC32"
1
I
..........................................................................
I
I
ODBC
módulodelnúcleo
Definiciones
del
""""~"""~""""""""""""""""""""""""1"""" )
""""""""""""""""""""""""-""""""""~
1
Definiciones API del nucleo ODBC-- versiones
de 32 bits
I
Declare Function SQLAllocConnect Lib "odbc32.dll" (ByVal henv&, phdbc&)
As Integer
Declare Function SQLAllocEnv Lib "odbc32.dll" (phenv&) As Integer
Declare Function SQLAllocStmt Lib "odbc32.dll" (ByVal hdbc&, phstmt&) As Integer
Declare Function SQLBindColLib "odbc32.dll" (ByVal hstmt&, ByValicol%, ByVal fCType%, rgbValue AsAny, ByVal cbValueMax&, pcbValue&) As Integer
Declare Function SQLCancel Lib "odbc32.dll" (ByVal hstmt&) As Integer
Declare Function SQLColAttributes Lib "odbc32.dll" (ByVal hstmt&, ByVal icol%,
ByVal fDescType%, rgbDesc As Any, ByVal cbDescMax%,
pcbDesc%, pfDesc&) As Integer
Declare Function SQLColAttributesString Lib "odbc32.dll" Alias
"SQLColAttributes" (ByVal hstmt&, ByValicol%, ByVal fDescType%,
ByVal rgbDesc AsString, ByVal cbDescMax%, pcbDesc%, pfDesc&) As
Integer
Declare Function SQLConnect Lib "odbc32.dll" (ByVal hdbc&, ByVal szDSN$,
ByVal cbDSN%, ByVal szUID$, ByVal cbUID%, ByVal szAuthStr$, ByVal cbAuthStr%)
As Integer
Declare Function SQLDescribeCol Lib"odbc32.dll" (ByVal hstmt&, ByValicol%, ByVal szColName$, ByVal cbColNameMax%, pcbColName%,pfSqlType%, pcbColDef&, -
113
pibScale8, pfNullable%) As Integer
Declare Function SQLDisconnect Lib "odbc32.dll" (ByVal hdbc&) As Integer
Declare Function SQLError Lib "odbc32.dll" (ByVal henv&,
ByVal hdbc&, ByVal hstmt&, ByVal szSqlState$, pfNativeError&, ByVal szErrorMsg$,
ByVal cbErrorMsgMax%, pcbErrorMsg%) As Integer
Declare Function SQLExecDirect Lib "odbc32.dll" (ByVal hstmt&, ByVal szSqlStr$,
ByVal cbSqlStr&) As Integer
Declare Function SQLExecute Lib "odbc32
.dll" (ByVal hstmt&) As Integer
Declare Function SQLFetch Lib "odbc32.dll" (ByVal hstmt&) As Integer
Declare Function SQLFreeConnect Lib "odbc32.dll" (ByVal hdbc&) As Integer
Declare Function SQLFreeEnv Lib "odbc32.dll" (ByVal henv&) As Integer
Declare Function SQLFreeStmt Lib "odbc32.dll" (ByVal hstmt&, ByVal
foption%) As Integer
Declare Function SQLGetCursorName Lib "odbc32.dll" (ByVal hstmt&,
ByVal szCursor$, ByVal cbCursorMax%, pcbCursor%)
As Integer
Declare Function SQLNumResultCols Lib "odbc32.dll" (ByVal
hstmt&, pccol%) As Integer
Declare Function SQLPrepareLib "odbc32.dll" (ByVal hstmt&, ByVal szSqlStr$,
ByVal cbSqlStr&) As Integer
Declare Function SQLRowCount Lib"odbc32.dll" (ByVal hstmt&, pcrow&) As Integer
Declare Function SQLSetCursorName Lib "odbc32.dll" (ByVal hstmt&,
ByVal szCursor$, ByVal cbCursor%) As Integer
Declare Function SQLSetParam Lib "odbc32.dll" (ByVal hstmt&, ByVal ipar%,
ByVal fCType%, ByVal fSqlType%, ByVal cbColDef&, ByVal ibScale%,
rgbValue As Any,pcbValue.5) As Integer
Declare Function SQLTransact Lib
"odbc32.dll" (ByVal henv&, ByVal hdbc&,
ByVal fType%) As Integer
I
1
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
extendidas
' 1 Definiciones
API
de ODBC
I
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
,
Prototipos de Nivel 1
Declare Function SQLBindParameter Lib "odbc32.dll" (ByVal hstmt&, ByVal ipar%,
ByVal fParamType5, ByValfCType%, ByVal fSqlType%, ByVal cbColDef&,
ByVal ibScale%, rgbValue As Any, ByVal cbValueMax&, pcbValue Long?
As As Integer
Declare Function SQLColumns Lib "odbc32.dll" (ByVal hstmt&,
szTblQualifier As Any, ByVal cbTblQualifier%, szTblOwner
As Any, ByVal cbTblOwner%, szTblName As Any, ByVal cbTblName%, szColName
As Any, ByVal cbColName%) As Integer
Declare Function SQLDriverConnect Lib "odbc32.dll" (ByVal hdbc&,
ByVal hWnd As Long, ByVal szCSIn$, ByValcbCSIn%, ByVal szCSOut$, ByVal cbCSMax%, cbCSOut%, ByVal fDrvrComp%) As Integer
Declare Function SQLGetConnectOption Lib "odbc32.dll" (ByVal hdbc&,
ByVal foption%, ByRef pvParam As Any) As Integer
Declare FunctionSQLGetConnectOptionString Lib "odbc32.dll" Alias"SQLGetConnectOption" (ByVal hdbc&, ByVal foption%, ByVal pvParam As String)
As Integer
Declare Function SQLGetData Lib "odbc32.dll" (ByVal hstmt&, ByVal icol%,
ByVal fCType%, ByVal rgbValue As String, ByVal cbValueMax&, pcbValue&)
As Integer
Declare Function SQLGetNumericData Lib "odbc32 .dll" Alias "SQLGetData"
(ByVal hstmt&, ByValicol%, ByVal fCType%, ByRef rgbValue As Any,
ByVal cbValueMax&, pcbValue&) As Integer
Declare Function SQLGetFunctions Lib "odbc32.dll" (ByVal
hdbc&, ByVal fFunction%, pfExists%) As Integer
Declare Function SQLGetInfo Lib "odbc32.dll" (ByVal hdbc&, ByVal fInfoType%,
ByRef rgbInfoValue AsAny, ByVal cbInfoMax%, cbInfoOut%) As Integer
dll" Alias "SQLGetInfo"Declare Function SQLGetInfoString Lib "odbc32.
(ByVal hdbc&, ByValfInfoType%, ByVal rgbInfoValue As String,
ByVal cbInfoMax%, cbInfoOut%) As Integer
115
Declare Function SQLGetStmtOption Lib "odbc32.dll" (ByVal hstmt&,
ByVal foption%, ByRef pvParam As Any) As Integer
Declare Function SQLGetStmtOptionString Lib
"odbc32.dll" Alias "SQLGetStmtOption" (ByVal hstmt&, ByVal
foption%, ByVal pvParam As String)As Integer
Declare Function SQLGetTypeInfo Lib "odbc32.dll" (ByVal hstmt&,
ByVal fSqlType%) As Integer
Declare Function SQLParamData Lib "odbc32.dll" (ByVal hstmt&,
prgbValue As Any) As Integer
Declare Function SQLPutDataLib "odbc32.dll" (ByVal hstmt&, rgbValue As A n y , ByVal cbValue&) As Integer
Declare Function SQLSetConnectOption Lib "odbc32.dll" (ByVal hdbc&,
ByVal foption%, ByVal vParam As Any) As Integer
Declare FunctionSQLSetConnectStringOption Lib "odbc32.dll" Alias
"SQLSetConnectOption" (ByVal hdbc&, ByVal foption%, vParam$) As Integer
Declare Function SQLSetStmtOption Lib "odbc32.dll" (ByVal
hstmt&, ByVal foption%, ByVal vPararn&) As Integer
Declare Function SQLSpecialColumns Lib "odbc32.dll" (ByVal
hstmt&, ByVal fColType%, szTblQualifier AsAny, ByVal cbTblQualifier%,
szTblOwner As Any, ByVal
cbTblOwner%, szTblName As Any, ByVal
cbTblName%, ByVal fScope%, ByVal fNullable%) As Integer
Declare Function SQLStatistics Lib
"odbc32.dll" (ByVal hstmt&,
As Any,
szTblQualifier As Any, ByVal cbTblQualifier8, szTblOwner
ByVal cbTblOwner%, szTblName As Any, ByVal cbTblName%, ByVal
fUnique%, ByVal fAccuracy%) As Integer
Declare Function SQLTables Lib
"odbc32.dll" (ByVal hstmt&,
szTblQualifier AsAny, ByVal cbTblQualifier%,szTbl0wnerAs A n y ,
ByVal cbTblOwner%, szTblName As Any, ByVal
cbTblName%, szTblType As Any, ByVal cbTblType%) As Integer
'
Prototipos de Nivel Level 2
I
Declare Function SQLBrowseConnect Lib "odbc32.dll" (ByVal hdbc&,
ByVal szConnStrInS, ByVal cbConnStrIn%, ByVal szConnStrOutS,
ByVal cbConnStrOutMax%, pcbConnStrOut%) As Integer
Declare Function SQLColumnPrivileges Lib "odbc32.dll" (ByVal hstmt&,
szTQf As Any, ByVal cbTQf%, szTOwn As Any, ByVal cbTOwn%, szTName
As Any, ByVal cbTName%, szColName As Any, ByVal cbColName%) As Integer
Declare Function SQLDrivers Lib"odbc32.dll" (ByVal henv&, ByValfDirection%, ByVal szDriverDesc$, ByVal cbDriverDescMaxB, pcbDriverDesc%,
ByVal szDriverAttr$, ByVal cbDrvrAttrMax%, pcbDrvrAttr%) As Integer
Declare Function SQLDataSources Lib
"odbc32.dll" (ByVal henv&,ByVal fDirectionR, ByVal szDSN$, ByVal cbDSNMax%, pcbDSN%,
ByVal szDescriptionS, ByVal cbDescriptionMax%, pcbDescription8) As Integer
Declare Function SQLDescribeParam Lib "odbc32.dll" (ByVal hstmt&, ByVal
ipar%, pfSqlType%, pcbColDef&, pibScale%, pfNullable%) As Integer
Declare Function SQLExtendedFetch Lib
"odbc32.dll" (ByVal hstmt&,ByVal fFetchType8, ByVal irow&, pcrow&, rgfRowStatus%) As Integer
Declare Function SQLForeignKeys Lib "odbc32.dll" (ByVal hstmt&, ByVal PTQual&,
ByVal PTQual%, ByVal PTOwnr&, ByValPTOwnr%, ByVal PTName&, ByVal PTName%,ByVal FTQual&, ByVal FTQf%, ByVal FTOwnr&, ByVal FTOwnr%, ByVal FTName&,
ByVal FTName%) As Integer
Declare Function SQLMoreResults Lib
"odbc32.dll" (ByVal hstmt&) As Integer
Declare Function SQLNativeSqlLib "odbc32.dll" (ByVal hdbc&, ByValszSqlStrJn$, ByVal cbSqlStrIn&, ByVal szSqlStrS, ByVal cbSqlStrMax&, pcbSqlStr&) As Integer
Declare Function SQLNumParams Lib"odbc32.dll" (ByVal hstmt&,pcpar%) As Integer
Declare Function SQLParamOptions Lib "odbc32.dll" (ByVal hstmt&, ByVal
crow%, pirow&) As Integer
Declare Function SQLPrimaryKeys Lib "odbc32.dll" (ByVal hstmt&,
szTblQualifier As Any, ByVal
cbTblQualifier%, szTblOwner As Any,ByVal cbTblOwner%, szTblName As Any, ByValcbTblName%) As Integer
Declare Function SQLProcedureColumns Lib "odbc32 .dll" (ByVal hstmt&,
-
116
szProcQualifier As Any, ByVal cbProcQualifier%, szProcOwner As Any,
As Any, ByVal cbProcOwner%, szProcName As Any, ByVal cbProcName%, szColName
ByVal cbColName%) As Integer
Declare Function SQLProcedures Lib "odbc32.dll" (ByVal hstmt&,
szProcQualifier As Any, ByVal cbProcQualifier%, szProcOwner
As Any, ByVal cbProcOwner%, szProcName As Any, ByVal cbProcName%) As Integer
Declare Function SQLSetPosLib "odbc32.dll" (ByVal hstmt&, ByVal irow%,
ByVal foption%, ByVal flock%) As Integer
Declare Function SQLSetScrollOptions Lib "odbc32.dll" (ByVal hstmt&,
ByVal fConcurrency%, ByVal crowKeyset&, ByVal crowRowset%) As Integer
Declare Function SQLTablePrivileges Lib "odbc32.dll" (ByVal
hstmt&, szTblQualifier As Any, ByVal cbTblQualifier%, szTblOwner
As Any, ByVal cbTblOwner%, szTblName As Any, ByVal cbTblName%)
As Integer
I
'
Declaraciones de 32 bits
Constantes y tipos de ODBC
1
'
Constantes de uso general
I
Global
Const
SQL-NTS
As
Long = -3
'NTS = Null
Terminated
String
Global Const SQL-SQLSTATE-SIZE As Long = 5
'size of SQLSTATE
Global Const SQL-MAX-MESSAGE-LENGTH As Long = 512 'message buffer size
'maximum data source name size
Global Const SQL-MAX-DSN-LENGTH As Long = 32
'
RETCODEs
1
Global
Global
Global
Global
Global
'
Const
Const
Const
Const
Const
SQL-ERROR As Long = -1
SQL-INVALID-HANDLE As Long = -2
SQL-NO-DATA-FOUND As Long = 100
SQL-SUCCESS As Long = O
SQL-SUCCESS-WITH-INFO As Long = 1
definiciones SQLFreeStmt
1
Global
Global
Global
Global
'
Const SQL-CLOSE As Long = O
Const SQL-DROP As Long = 1
Const SQL-UNBIND As Long = 2
Const SQL-RESET-PAWS As Long = 3
definiciones SQLSetParam
I
Global Const SQL-C-DEFAULT As Long = 9 9
'
definiciones SQLTransact
I
Global Const SQL-COMMIT As Long = O
Global Const SQL-ROLLBACK As Long
= 1
'
Tipos de datos estándar SQL, usando los tipos ANSI
1
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-CHAR As Long = 1
Const SQL-NUMERIC As Long = 2
Const SQL-DECIMAL As Long
= 3
Const SQL-INTEGER As Long = 4
Const SQL-SMALLINT As Long = 5
Const SQL-FLOAT As Long = 6
ConstSQL-REAL As Long = 7
Const SQL-DOUBLE As Long
= 8
ConstSQL-VARCHAR As Long = 12
Global Const SQL-TYPE-MIN As Long = 1
Global Const SQL-TYPE-NULL As Long = 0
117
Global Const SQL-TYPE-MAX As Long = 12
'
Tipos de datos de C asignados a tiposde datos SQL
I
Global
Global
Global
Global
Global
'
'
I
Const SQL-C-CHAR As Long = SQL-CHAR
Const SQL-C-LONG As Long = SQL-INTEGER
Const SQL-C-SHORT As Long = SQL-SMALLINT
Const SQL-C-FLOAT As Long = SQL-REAL
Const SQL-C-DOUBLE As Long = SQL-DOUBLE
'CHAR,VARCHAR,DECIMAL,NUMERIC
'INTEGER
'SMALLINT
' REAL
'FLOAT,DOUBLE
Constantes de estado de NULL. Se usan en SQLColumns, SQLColAttributes,
SQLDescribeCol y SQLSpecialColumns para describirla capacidad de nulos
de una columna en una tabla. SQL-NULLABLE-UNKNOWN sólo se puede devolver
por SQLDescribeCol o SQLColAttributes. Se usa cuando el meta-datos de
DBMS no contiene esta información.
I
Global Const SQL-NO-NULLS As Long = O
Global Const SQL-NULLABLE As Long= 1
Global Const SQL-NULLABLE-UNKNOWN As Long = 2
'
Valores especiales de longitud
1
Global Const SQL-NULL-DATA As Long
= -1
Global Const SQL-DATA-AT-EXEC As Long = -2
'
Definiciones de SQLColAttributes
1
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-COLUMN-COUNT As Long = O
Const SQLCOLUMN-NAME As Long = 1
Const SQLICOLUMN-TYPE As Long
= 2
Const SQL-COLUMN-LENGTH As Long = 3
Const SQL-COLUMN-PRECISION As Long = 4
Const SQL-COLUMN-SCALE As Long = 5
Const SQL-COLUMN DISPLAY-SIZE As Long= 6
Const SQL-COLUMNINULLABLE As Long
= 7
Const SQL-COLUMN-UNSIGNED As Long = 8
Const SQL-COLUMN-MONEY As Long = 9
Const SQL-COLUMN-UPDATABLE As Long
= 10
Const SQL-COLUMN-AUTO-INCREMENT As Long = 11
Const SQL-COLUMN-CASE-SENSITIVE As Long = 12
Const SQL-COLUMN-SEARCHABLE As Long = 13
Const SQL-COLUMN-TYPE-NAME As Long = 14
Const SQL-COLUMN TABLE-NAME As Long = 15
Const SQL COLUMN-OWNER-NAME As Long = 16
Const SQL~COLUMN~QUALIFIER-NAMEAs Long = 17
Const SQL-COLUMN-LABEL As Long = 18
Const SQL-COLATT-OPT-MAX As Long= SQL-COLUMN-LABEL
Valores auxiliares de SQLColAttributes paraSQL-COLUMN-UPDATABLE
I
Global Const SQL-ATTR-READONLY As Long = O
Global Const SQL-ATTRWRITE As Long = 1
Global ConstSQL-ATTR-READWRITE -UNKNOWN As
'
'
Long
= 2
Valores auxiliares de SQLColAttributes para SQL-COLUMN-SEARCHABLE
También se usa en SQLGetInfo
1
Global
Global
Global
Global
Const SQL-UNSEARCHABLE As Long= O
Const SQL-LIKE-ONLY As Long = 1
Const SQL-ALL-EXCEPT-LIKE As Long = 2
Const SQL-SEARCHABLE As Long= 3
118
Definiciones de SQLError
I
Global Const SQL-NULL-HENV As Long = O
Global Const SQL-NULL-HDBC As Long = O
Global Const SQL-NULL-HSTMT As Long = O
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Definiciones
extendidas
globales
de ODBC
I
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Definiciones y funciones de Nivel 1
' Constantes de interés general
I1
I
1
Global Const SQL-MAX-OPTION-STRING-LENGTH
=
256
' Códigos de retorno adicionales
1
Global Const SQL-STILL-EXECUTING As Long= 2
Global Const SQL-NEED-DATA As Long= 99
' Tipos de datos extendidosde SQL
1
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
= 9
Const SQL-DATE As Long
Const SQL-TIME As Long = 10
Const SQL-TIMESTAMP As Long
= 11
Const SQL-LONGVARCHAR As Long
= -1
Const SQL-BINARY As Long
= -2
Const SQL-VARBINARY As Long
= -3
Const SQL-LONGVARBINARY As Long
= -4
Const SQL-BIGINT As Long
= -5
Const SQL-TINYINT As Long
= -6
Const SQL-BIT As Long = -1
Const SQL-TYPE-DRIVER-START As Long = -80
Tipos de datos de C asignados a tipos
de datos de SQL
I
Global Const SQL-SIGNED-OFFSET As Long = -20
Global Const SQL-UNSIGNED-OFFSET As Long
= -22
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-C-DATE As Long = SQL-DATE
Const SQL-C-TIME As Long = SQL-TIME
Const SQL-C-TIMESTAMP As Long = SQL-TIMESTAMP
Const SQL-C-BINARY As Long
= SQL-BINARY
Const SQL-C-BITAs Long = SQL-BIT
Const SQL-C-TINYINT As Long= SQL-TINYINT
Const SQL-C-SLONG As Long = SQL-C-LONG + SQL-SIGNED-OFFSET
Const SQL-C-SSHORT As Long = SQL-C-SHORT + SQL-SIGNED-OFFSET
Const SQL-C-STINYINTAs Long = SQL-TINYINT + SQL-SIGNED-OFFSET
Const SQL-C-ULONG As Long = SQL-C-LONG + SQL-UNSIGNED-OFFSET
Const SQL-C-USHORT As Long = SQL-C-SHORT + SQL-UNSIGNED-OFFSET
Const SQL-C-UTINYINT As Long = SQL-TINYINT + SQL-UNSIGNED-OFFSET
Const SQL-C-BOOKMARK As Long= SQL-C-ULONG
Global Const SQL-ALL-TYPESAs Long
=
O
I
'
Estructuras para marcas de fecha y hora
1
Type DATE-STRUCT
As Integer
year
As Integer
month
119
Integer
Asday
End Type
Type TIME-STRUCT
hour
As Integer
minute
As Integer
second
As Integer
End Type
Type TIMESTAMP STRUCT
year
As- Integer
Integer
As
month
Integer
As
day
Integer
As hour
Integer
minute
As
second
As
Integer
Long
fractionAs
End Type
' Opciones de SQLDriverConnect
1
Global Const SQL-DRIVER-NOPROMPT As Long = O
Global Const SQL-DRIVER-COMPLETE As Long = 1
Global Const SQL-DRIVER-PROMPT As Long = 2
Global ConstSQL-DRIVER-COMPLETE -REQUIRED As
Long
= 3
' Valores especiales de retorno para SQLGetData
1
Global Const SQL-NO-TOTAL As Long = -4
Extensiones de SQLSetParam
1
Global Const SQL-DEFAULT-PARAM As Long = -5
Global Const SQL-IGNORE As Long= -6
Global Const SQL-LEN-DATA-AT-EXEC-OFFSET
As Long = -100
' Definiciones para SQLGetFunctions
' Funciones del nucleo
1
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-API-SQLALLOCCONNECT As Long = 1
Const SQL API-SQLALLOCENV As Long= 2
Const SQLAPI SQLALLOCSTMT AS Long = 3
Const SQLAPI~SQLBINDCOLAS Long = 4
Const SQLAPI SQLCANCEL AS Long = 5
Const SQLAPI~SQLCOLATTRIBUTESAs Long = 6
Const SQL-API-SQLCONNECT AS Long = 7
Const SQLAPI-SQLDESCRIBECOL As Long = 8
Const SQL API SQLDISCONNECT As Long
= 9
Const SQLAPI~SQLERRORAS Long = 10
Const SQL-API-SQLEXECDIRECT As Long = 11
Const SQL API SQLEXECUTE As Long= 12
Const SQLIAPIISQLFETCH As Long
= 13
Const SQL API-SQLFREECONNECT As Long= 14
Const SQLAPI SQLFREEENV As Long= 15
Const SQLAPI-SQLFREESTMT As Long = 16
Const SQLIAPI~SQLGETCURSORNAMEAs Long = 17
Const SQL API-SQLNUMRESULTCOLS As Long= 18
Const SQLAPI-SQLPREPARE AS Long = 19
Const SQL-API-SQLROWCOUNT As Long = 20
Const SQL API SQLSETCURSORNAME As Long
= 21
Const SQL~API~SQLSETPARAM
AS Long = 22
Global Const SQL-API-SQLTRANSACT As Long= 23
Global Const SQL-NUM-FUNCTIONS As Long = 23
Global Const SQL-EXT-API-START As Long = 40
' Funciones de nivel 1
1
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL API SQLCOLUMNS As Long= 40
Const SQLAPIISQLDRIVERCONNECT As Long = 41
Const SQL~API-SQLGETCONNECTOPTLONAS Long = 42
Const SQL-API-SQLGETDATA As Long = 43
= 44
Const SQL API SQLGETFUNCTIONS As Long
Const SQLAPI-SQLGETINFO AS Long = 45
AS Long = 46
Const
Const SQLAPI SQLGETTYPEINFO AS Long = 47
= 48
Const SQLIAPIISQLPARAMDATA As Long
Const SQL API-SQLPUTDATA As Long= 49
Const SQL~API-SQLSETCONNECTOPTIONAS Long = 50
Const SQL-API-SQLSETSTMTOPTION As Long = 51
Const SQL-API-SQLSPECIALCOLUMNS As Long = 52
Const SQL-API-SQLSTATISTICS As Long = 53
Const SQLAPI-SQLTABLES As Long = 54
SQLAPIISQLGETSTMTOPTION
' Funciones de nivel2
1
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-API-SQLBROWSECONNECT As Long = 55
= 56
Const SQL API-SQLCOLUMNPRIVILEGES As Long
Const SQLAPI SQLDATASOURCES AS Long = 57
Const SQL-API-SQLDESCRIBEPARAM AS Long = 58
Const SQLAPI~SQLEXTENDEDFETCHAS Long = 59
= 60
Const SQLAPI SQLFOREIGNKEYS As Long
Const SQLAPIZSQLMORERESULTS As Long = 61
= 62
Const SQL API SQLNATIVESQL As Long
Const SQLAPIZSQLNUMPARAMS As Long = 63
= 64
Const S Q L A P I SQLPARAMOPTIONS As Long
Const SQL-API-SQLPRIMARYKEYS As Long = 65
Const SQLAPI-SQLPROCEDURECOLUMNS As Long = 66
Const SQLAPI-SQLPROCEDURES As Long = 67
Const SQLAPI-SQLSETPOS As Long = 68
Const S Q L A P I ~ S Q L S E T S C R O L L O P T I O N S AS Long = 69
Const SQL-API-SQLTABLEPRIVILEGES As Long = 7 0
Const SQL-API-SQLDRIVERS As Long = 71
= 72
Const SQL API SQLBINDPARAMETER As Long
"
Global Const SQL-EXT-API-LAST As Long = 72
Global Const SQL-API-ALL-FUNCTIONS As Long = 0
Global Const SQL-NUM-EXTENSIONS As Long = (SQL-EXT-API-LAST - SQL-EXT-API-START + 1 )
'
Definiciones para SQLGetInfo
I
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-INFO-FIRST As Long = O
Const SQL-ACTIVE-CONNECTIONS As Long
= O
Const SQL-ACTIVE-STATEMENTS As Long = 1
Const SQL-DATA-SOURCE-NAME As Long = 2
ConstSQL-DRIVER-HDBC As Long = 3
Const SQL-DRIVER-HENV As Long = 4
Const SQL-DRIVER-HSTMT As Long = 5
Const SQL-DRIVER-NAME As Long = 6
ConstSQL-DRIVER-VER As Long = 7
= 8
Const SQL-FETCH-DIRECTION As Long
Const SQL-ODBC-API-CONFORMANCE As Long = 9
121
Global
Global
Global
Global
Global
Global
Const SQL-ODBC-VER As Long = 10
Const SQL-ROW-UPDATES As Long = 11
Const SQL-ODBC-SAG-CLI-CONFORMANCE As Long = 12
Const SQL-SERVER-NAME As Long = 13
Const SQL-SEARCH-PATTERN ESCAPE As Long= 14
Const SQL-ODBC-SQL-CONFO&ANANCE
As Long = 15
Global Const SQL-DBMS-NAME As Long = 17
Global Const SQL-DBMS-VER As Long = 18
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-ACCESSIBLE-TABLES As Long = 19
Const SQL-ACCESSIBLE-PROCEDURES As Long = 20
Const SQL-PROCEDURES As Long
= 21
= 22
Const SQL-CONCAT-NULL-BEHAVIOR As Long
Const SQL-CURSOR-COMMIT-BEHAVIOR As Long = 23
Const SQL-CURSOR-ROLLBACK-BEHAVIOR As Long = 24
As Long = 25
Const SQL-DATA-SOURCE-READ_ONLY
Const SQL-DEFAULT-TXN-ISOLATION As Long = 26
Const SQL-EXPRESSIONS-IN ORDERBY As Long= 27
Const SQL-IDENTIFIER-CASE As Long
= 28
Const SQL-IDENTIFIER-QUOTE-CHAR As Long = 29
Const SQL-MAX-COLUMN-NAME-LEN As Long = 30
Const SQL-MAX-CURSOR-NAME-LEN As Long= 31
Const SQL-MAX-OWNER-NAME LEN As Long = 32
Const SQL-MAX-PROCEDURE iAME LEN As Long= 33
Const SQL-MAX-QUALIFIERINAMEILEN As Long = 34
Const SQL-MAX-TABLE-NAME LEN As Long = 35
Const SQL-MULT-RESULT-SETS As Long = 36
Const SQL-MULTIPLE-ACTIVE-TXN As Long = 37
= 38
Const SQL-OUTER-JOINS As Long
Const SQL-OWNER-TERM As Long = 39
Const SQL-PROCEDURE-TERM As Long = 40
Const SQL QUALIFIER-NAME SEPARATOR As Long= 41
Const SQLIQUALIFIER-TERMAS Long = 42
Const SQL-SCROLL-CONCURRENCY As Long = 43
Const SQL-SCROLL-OPTIONS As Long = 44
Const SQL-TABLE-TERM As Long = 45
Const SQL-TXN-CAPABLE As Long = 46
Const SQL-USER-NAME As Long = 47
Global
Global
Global
Global
Global
Const SQL-CONVERT-FUNCTIONS As Long = 48
Const SQL-NUMERIC-FUNCTIONS As Long = 49
Const SQL-STRING-FUNCTIONS As Long = 50
Const SQL-SYSTEM-FUNCTIONS As Long = 51
Const SQL-TIMEDATE-FUNCTIONS As Long= 52
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
= 53
Const SQL-CONVERT-BIGINT As Long
Const SQL-CONVERT-BINARY As Long = 54
Const SQL-CONVERT-BIT As Long = 55
Const SQL-CONVERT-CHAR As Long = 56
Const SQL-CONVERT-DATE As Long = 57
Const SQL-CONVERT-DECIMAL A s Long = 58
Const SQL-CONVERT-DOUBLE As Long = 59
Const SQL-CONVERT-FLOAT As Long = 60
Const SQL-CONVERT-INTEGER As Long = 61
Const SQL-CONVERT-LONGVARCHARAs Long = 62
Const SQL-CONVERT-NUMERIC As Long = 63
Const SQL-CONVERT-REAL As Long = 64
Const SQL-CONVERT-SMALLINT As Long = 65
Const SQL-CONVERT-TIME As Long
= 66
Const SQL-CONVERT-TIMESTAMP As Long = 67
Const SQL-CONVERT-TINYINT As Long
= 68
122
Global Const SQL-CONVERT-VARBINARY As Long
= 69
Global Const SQL-CONVERT-VARCHAR As Long = 70
Global Const SQL-CONVERT-LONGVARBINARY As Long = 71
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-TXN-ISOLATION-OPTION As Long = 72
Const SQL-ODBC-SQL-OPT-IEF As Long = 73
Const SQL-CORRELATION-NAME As Long = 74
Const SQL-NON-NULLABLE-COLUMNS As Long = 75
Const SQL-DRIVER-HLIB As Long = 76
Const SQL-DRIVER-ODBC-VER As Long = 77
Const SQL-LOCK-TYPES As Long = 78
Const SQL-POS-OPERATIONS As Long = 79
Const SQL-POSITIONED-STATEMENTS As Long = 80
Const SQL GETDATA-EXTENSIONS As Long= 81
Const SQL~BOOKMARK-PERSISTENCEAs Long = 82
Const SQL-STATIC-SENSITIVITY As Long
= 83
Const SQL-FILE-USAGE As Long = 84
= 85
Const SQL-NULL-COLLATION As Long
Const SQLALTER-TABLE As Long = 86
Const SQL-COLUMN-ALIAS As Long= 87
Const SQL-GROUP-BY As Long = 88
Const SQL-KEYWORDS As Long
= 89
Const SQL-ORDER-BY-COLUMNS-IN-SELECT As Long = 90
Const SQL-OWNER-USAGE As Long
= 91
= 92
Const SQL QUALIFIER-USAGE As Long
Const SQLlQUOTED-IDENTIFIER-CASE As Long = 93
Const SQL-SPECIAL-CHARACTERS As Long = 94
Const SQL-SUBQUERIES As Long= 95
Const SQL-UNION As Long = 96
Const SQL-MAX-COLUMNS-IN-GROUP-BY As Long = 97
Const SQL-MAX-COLUMNS-IN-INDEX As Long = 98
As Long = 99
Const SQL-MAX-COLUMNS-IN-ORDER_BY
Const SQL-AX-COLUMNS-IN-SELECT As Long = 100
Const SQL-MAX-COLUMNS-IN-TABLE As Long = 1 0 1
Const SQL-MAX-INDEX-SIZE As Long= 102
Const SQL-MAX-ROW-SIZE-INCLUDES-LONG As Long = 103
Const SQL-MAX-ROW-SIZE As Long = 104
Const SQLMAX STATEMENT-LEN As Long = 105
Const SQL-MAXITABLES-IN-SELECT As Long = 106
Const SQLIMAX-USER-NAME-LEN As Long = 107
Const SQL-MAX-CHAR-LITERAL-LEN As Long = 108
Const SQL-TIMEDATE-ADD-INTERVALS As Long = 109
Const SQL-TIMEDATE-DIFF-INTERVALS As Long = 110
Const SQL-NEED-LONG-DATA-LEN As Long = 1 1 1
Const SQL
MAX-BINARY-LITERAL-LEN As Long = 112
Const SQLILIKE-ESCAPE-CLAUSE As Long = 113
Const SQL-QUALIFIER-LOCATION As Long = 114
= SQL-QUALIFIER-LOCATION
Global Const SQL-INFO-LAST As Long
Global Const SQL-INFO-DRIVER-START As Long = 1 0 0 0
Máscaras de bits para "SQL-CONVERT-"
I
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-CVT-CHAR As Long = &HI&
= &HZ&
Const SQL-CVT-NUMERIC As Long
Const SQL-CVT-DECIMAL As Long = &H4&
Const SQL-CVT-INTEGER As Long = &Ha&
Const SQL-CVT-SMALLINT As Long = &H10&
Const SQL-CVT-FLOAT As Long = &H20&
Const SQL-CVT-REAL As Long = &H40&
Const SQL-CVT-DOUBLE As Long = &H8O&
123
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-CVT-VARCHAR As Long = &H100&
Const SQL-CVT-LONGVARCHAR As Long = &H200&
Const SQL-CVT-BINARY As Long = &H400&
= &H800&
Const SQL-CVT-VARBINARY As Long
Const SQL-CVT-BIT As Long = &H1000&
Const SQL-CVT-TINYINT As Long = &H2000&
Const SQL-CVT-BIGINT As Long = &H4000&
Const SQL-CVT-DATE As Long = &H8000&
Const SQL-CVT-TIME As Long = &H10000
Const SQL-CVT-TIMESTAMP As Long= &H20000
Const SQL-CVT-LONGVARBINARY As Long
= &H40000
' Funciones de conversión
,
Global
Const
SQL
-FN-CVT-CONVERT As
Long= &H1&
' Funciones de cadena
1
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-FN-STR-CONCAT As Long = &H1&
Const SQL-FN-STR-INSERT As Long= &H2&
Const SQL-FN-STR-LEFT As Long = &H4&
Const SQL-FN STR-LTRIM As Long= &H8&
Const SQL-FNISTR-LENGTH As Long = &H10&
Const SQL-FN-STR-LOCATE As Long = &H20&
Const SQL-FN-STR-LCASE As Long = &H40&
Const SQL-FN-STR-REPEAT As Long = &H80&
Const SQLFN-STR-REPLACE As Long = &H100&
Const SQLIFN-STR-RIGHT As Long = &H200&
Const SQL FN-STR-RTRIM As Long
= &H400&
= &H800&
Const SQLIFN STR SUBSTRING As Long
Const SQL FNISTRIUCASE As Long= &H1000&
Const SQLIFN-STR-ASCII As Long
= &H2000&
Const SQL-FN-STR-CHAR As Long = &H4000&
Const SQL-FN-STR-DIFFERENCE As Long= &H8000&
Const SQL-FN-STR-LOCATE 2 As Long= &H10000
Const SQL-FN-STR-SOUNDEX As Long = &H20000
Const SQL-FN-STR-SPACE As Long = &H40000
' Funciones numéricas
I
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-FN-NUM-ABS As Long = &H1&
Const SQL-FN-NUM-ACOS As Long = &H2&
Const SQL-FN-NUM-ASIN As Long = &H4&
Const SQL-FN-NUM-ATAN As Long = &H8&
Const SQL-FN-NUM-ATAN2 As Long = &H10&
Const SQL-FN-NUM-CEILING As Long = &H20&
Const SQL-FN-NUM-COS As Long = &H40&
Const SQL-FN-NUM-COT As Long = &H80&
Const SQL-FN-NUM-EXP As Long = &H100&
Const SQL-FN-NUM-FLOOR As Long= &H200&
Const SQL-FN-NUM-LOG As Long = &H400&
Const SQL-FN-NUM-MOD As Long = &H800&
Const SQL-FN-NUM-SIGN As Long = &H1000&
Const SQL-FN-NUM-SIN As Long = &H2000&
Const SQL-FN-NUM-SQRT As Long = &H4000&
Const SQL-FN-NUM-TAN As Long = &H8000&
Const SQL-FN-NUM-PI As Long = &H10000
Const SQL FN-NUM-RAND As Long = &H20000
Const SQLIFN-NUM-DEGREES As Long = &H40000
Const SQL-FN-NUM-LOG10 As Long = &H80000
124
Global
Global
Global
Global
Const SQL-E'N-NUM-POWER As Long = &H100000
Const SQL-FN-NUM-RADIANS As Long = &H200000
Const SQL-FN-NUM-ROUND As Long = &H400000
Const SQL-FN-NUM-TRUNCATE As Long = &H800000
' Funciones de fecha y hora
1
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-FN-TD-NOW As Long = &HI&
Const SQL-FN-TD-CURDATE As Long = &H2&
= &H4&
Const SQL-FN-TD-DAYOFMONTH As Long
Const SQL-FN-TD-DAYOFWEEK As Long = &HE&
Const SQL-FN-TD-DAYOFYEAR As Long = &H10&
Const SQL-E'N-TD-MONTH As Long = &H20&
Const SQL-FN-TD-QUARTER As Long = &H40&
Const SQL-FT-TD-WEEK As Long = &H80&
Const SQL-FN-TD-YEAR As Long = &H100&
Const SQL-FN-TD-CURTIME As Long = &H200&
Const SQL-FN-TD-HOUR As Long = &H400&
Const SQL-FN-TD-MINUTE As Long = &H800&
Const SQL-FN-TD-SECOND As Long = &H1000&
I
Global ConstSQL-FN-TD-TIMESTAMPADD As Long = &H2000&
Global Const SQL-FN-TD-TIMESTAMPDIFFAs Long = &H4000&
Global Const SQL-FN-TD-DAYNAME As Long = &H8000&
Global ConstSQL-FN-TD-MONTHNAME As Long= &H10000
' Funciones del sistema
1
Global Const SQL-FN-SYS-USERNAME As Long = &H1&
Global Const SQL-FN,-SYS-DBNAME As Long= &H2&
Global Const SQL-FN-SYS-IFNULL As Long = &H4&
Intervalos de fecha y hora
I
I
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-FN-TSI-FRAC-SECOND As Long = &H1&
Const SQL-FN-TSI-SECOND As Long = &H2&
Const SQL-FN-TSI-MINUTE As Long = &H4&
Const SQL-FN-TSI-HOUR As Long = &H8&
Const SQL-FN-TSI-DAY As Long = &H10&
Const SQL-FN-TSI-WEEK As Long = &H20&
Const SQL-FN-TSI-MONTH As Long= &H40&
Const SQLFN-TSI-QUARTER As Long = &H80&
Const SQLIFN-TSI-YEAR As Long = &H100&
acomodación ODBC-API
1
Global Const SQL-OAC-NONE As Long = O
Global Const SQL-OAC-LEVEL1 As Long = 1
Global Const SQL-OAC-LEVEL2 As Long = 2
' acomodación SAG-CLI
I
Global Const SQL-OSCC-NOT-COMPLIANT As Long = O
Global Const SQL-OSCC-COMPLIANT As Long= 1
' acomodación ODBC-SQL
1
Global Const SQL-OSC-MINIMUM As Long= O
125
Global Const SQL-OSC-CORE As Long = 1
Global Const SQL-OSC-EXTENDED As Long = 2
' Comportamiento en concatenacih
I
Global Const SQL-CB-NULL As Long = O
Global Const SQL-CB-NON-NULL As Long= 1
' Comportamiento del cursor
I
Global Const SQL-CB-DELETE As Long = O
Global Const SQL-CB-CLOSE As Long
= 1
Global Const SQL-CB-PRESERVE As Long = 2
' Identificación de las letras
1
Global
Global
Global
Global
Const SQL-IC-UPPER As
Const SQL-IC-LOWER As
Const SQL-IC-SENSITIVE
Const SQL-IC-MIXED As
Long = 1
Long = 2
As Long
Long = 4
=
3
' Transaction capable
I
Global Const SQL-TC-NONE As Long = O
Global Const SQL-TC-DML As Long = 1
Global Const SQL-TCALL As Long = 2
1
Global Const SQL-TC-DDL-COMMIT As Long
Global Const SQL-TC-DDL-IGNORE As Long
=
=
3
4
' Capacidad de transacción
I
Global
Global
Global
Global
Const SQL-SO-FORWARD-ONLY As Long = &H1&
Const SQL-SO-KEYSET-DRIVEN As Long= &HZ&
Const SQL-SO-DYNAMIC As Long = &H4&
Const SQL-SO-MIXED As Long = &H8&
1
Global Const SQL-SO-STATIC As Long
=
&H10&
' Máscaras de optimización de desplazamiento
I
Global
Global
Global
Global
Const SQL-SCCO-READ-ONLY As Long = &H1&
Const SQL-SCCO-LOCK As Long = &H2&
Const SQL-SCCO-OPT-ROWVER As Long = &H4&
Const SQL-SCCO-OPT-VALUES As Long = &H8&
' Traer máscaras de opciones de dirección
1
Global
Global
Global
Global
Global
Global
Global
Const SQL-FD-FETCH-NEXT As Long = &H1&
Const SQL-FD-FETCH-FIRST As Long = &H2&
Const SQL-FD-FETCH-LAST As Long = &H4&
Const SQL-FD-FETCH-PRIOR As Long = &H8&
Const SQL-FD-FETCH-ABSOLUTE As Long = &H10&
Const SQL-FD-FETCH-RELATIVE As Long = &H20&
Const SQL-FD-FETCH-RESUME As Long = &H40&
I
Global Const SQL-FD-FETCH-BOOKMARK As Long
=
&H80&
' Máscaras de opción de transacción para aislamiento
126
I
Global
Global
Global
Global
Global
Const SQL-TXN-READ-UNCOMMITTED As Long = &H1&
Const SQL-TXN-READ-COMMITTED As Long = &H2&
Const SQL-TXN-REPEATABLE-READ As Long = &H4&
Const SQL-TXN-SERIALIZABLE As Long = &H8&
Const SQL-TXN-VERSIONING As Long = &H10&
' Nombre de correlación
1
Global Const SQL-CNNONE As Long = O
Global Const SQL-CN-DIFFERENT As Long = 1
Global Const SQL-CN-ANY As Long = 2
Columnas
queno permiten
nulos
1
Global Const SQL-NNC-NULL As Long = O
Global Const SQL-NNC-NON-NULL As Long
=
1
I
' Ordenación de nulos
1
Global
Global
Global
Global
'
Const
Const
Const
Const
SQL-NC-HIGH As Long = O
SQL-NC-LOW As Long = 1
SQL-NC-START As Long = 2
SQL-NC-END As Long = 4
Uso de archivo
I
Global ConstSQL-FILE-NOT-SUPPORTED As Long = O
Global Const SQL-FILE-TABLE As Long = 1
Global Const SQL-FILE-QUALIFIER As Long = 2
' Máscaras para extensiones SQLGetData
1
Global
Global
Global
Global
Const SQL-GD-ANY-COLUMN As Long = &HI&
Const SQL-GDANY-ORDER As Long = &H2&
Const SQL-GD-BLOCK As Long = &H4&
Const SQL-GD-BOUND As Long = &HE&
' Modificar una tabla
1
Global Const SQL-AT-ADD-COLUMN As'Long = 1
Global ConstSQL-AT-DROP-COLUMN As Long = 2
' Máscaras para instruccionesde posicionamiento
I
Global Const SQL-PS-POSITIONED-DELETE As Long = &HI&
Global Const SQL PS-POSITIONED-UPDATE As Long = &H2&
Global Const SQLIPS-SELECT-FOR-UPDATE As Long = &H4&
Ordenar por
I
Global ConstSQL-GB-NOT-SUPPORTED As Long = O
Global Const SQL-GB-GROUP-BY-EQUALS_SELECT
As Long = 1
Global Const SQL-GB-GROUP-BY-CONTAINS-SELECT As Long = 2
Global Const SQL-GB-NO-RELATION As Long = 3
,
Máscaras de u s o de propietario
Global Const SQL-OU-DML-STATEMENTS As Long = &H1&
Global Const SQL OU PROCEDURE-INVOCATION As Long= &H2&
As Long = &H4&
Global Const SQL~OU~TABLE-DEFINITION
127
Global Const SQL-OU-INDEX-DEFINITION As Long = &H8&
Global Const SQL-OU-PRIVILEGE-DEFINITION As Long = &H10&
' Máscaras de usuario cualificado
,
Global
Global
Global
Global
Global
Const SQL-QU-DML-STATEMENTS As Long = &H1&
= &H2&
Const SQL-QU-PROCEDURE-INVOCATION As Long
Const SQL-QU-TABLE-DEFINITION As Long = &H4&
Const SQL-QU-INDEX-DEFINITION As Long = &H8&
Const SQL-QU-PRIVILEGE-DEFINITION As Long = &H10&
' Máscaras de subconsultas
I
Global
Global
Global
Global
Global
Const SQL-SQ-COMPARISON As Long = &H1&
Const SQL-SQ-EXISTS As Long = &H2&
Const SQL-SQ-IN As Long = &H4&
Const SQL-SQ-QUANTIFIED As Long = &Ha&
Const SQL-SQ-CORRELATED-SUBQUERIES As Long = &H10&
Máscaras de unión
1
Global Const SQL U-UNION As Long = &H1&
Global Const SQLIU-UNION-ALL As Long = &H2&
' Persistencia de Bookmark
1
Global
Global
Global
Global
Global
Global
Global
Const SQL-BP-CLOSE As Long = &H1&
Const SQL-BP-DELETE As Long = &H2&
Const SQL-BP-DROP As Long = &H4&
Const SQL BP-TRANSACTION As Long = &H8&
Const SQL-BP UPDATE As Long= &H10&
Const SQLBPIOTHER-HSTMT As Long = &H20&
= &H40&
Const SQL-BP-SCROLL As Long
' Sensibilidad estática
1
Global Const SQL-SS-ADDITIONS As Long = &HI&
Global Const SQL-SS-DELETIONS As Long = &H2&
Global Const SQL-SS-UPDATES As Long = &H4&
' Máscaras de bloqueo de tipos
1
Global Const SQL LCK NO-CHANGE As Long = &H1&
Global Const SQL-LCK-EXCLUSIVE As Long = &H2&
Global Const SQL~LCK~UNLOCK
As Long = &H4&
Máscaras de operaciones de posicionamiento
1
Global
Global
Global
Global
Global
I
Const SQL-POS-POSITION As Long = &H1&
Const SQL-POS-REFRESH As Long = &H2&
Const SQLPOS UPDATE As Long= &H4&
Const SQLIPOSIDELETE As Long
= &H8&
Const SQL-POS-ADD As Long = &H10&
Calificar la localización
1
Global Const SQL-QL-START As Long = 1
Global Const SQL-QL-END As Long = 2
Opciones para SQLGetStmtOption/SQLSetStmtOption
I
Global
Const
SQL
-QUERY-TIMEOUT
As
Long
= O
128
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-"ROWS
As Long = 1
Const SQL-NOSCAN As Long = 2
Const SQL-MAX-LENGTH As Long = 3
Const SQLASYNC-ENABLE As Long = 4
Const SQL-BIND-TYPE As Long = 5
Const SQL-CURSOR-TYPE As Long = 6
Const SQL-CONCURRENCY As Long= I
Const SQL-KEYSET-SIZE As Long = 8
Const SQL-ROWSET-SIZE As Long = 9
Const SQL-SIMULATE-CURSOR As Long = 10
Const SQL-RETRIEVE-DATA As Long = 11
Const SQL-USE-BOOKMARKS As Long = 1 2
Const SQL-GET-BOOKMARK As Long = 13
Const SQL-ROW-NUMBER As Long = 14
Global Const SQL-STMT-OPT-MAX As Long = SQL-ROW-NUMBER
' Opciones y valores predeterminadospara instrucciones
I
Global Const SQL-QUERY-TIMEOUT-DEFAULT As Long = O
Global Const SQL-MAX-ROWS-DEFAULT As Long= O
Global Const SQL-NOSCAN-OFF As Long
= O
Global Const SQL-NOSCAN-ON As Long= 1
Global Const SQL-NOSCAN-DEFAULT As Long
= SQL-NOSCAN-OFF
Global Const SQL-MAX-LENGTH-DEFAULT As Long
= O
Global Const SQL-ASYNC-ENABLE-OFF As Long = O
Global Const SQL-ASYNC-ENABLE-ON As Long = 1
Global Const SQL-ASYNC-ENABLE-DEFAULT As
Long
= SQL-ASYNC-ENABLE-OFF
Global Const SQL-BIND-BY-COLUMN As Long
Global
Global
Global
Global
Global
Global
Global
Global
=
0
Const SQL-CONCUR-READ-ONLY As Long
= 1
Const SQL-CONCUR-LOCK As Long= 2
Const SQL-CONCUR-ROWVER As Long
= 3
Const SQL-CONCUR-VALUES As Long
= 4
Const SQL-CURSOR-FORWARD-ONLYAs Long = O
Const SQL-CURSOR-KEYSET-DRIVEN As Long = 1
Const SQL-CURSOR-DYNAMIC As Long
= 2
Const SQL-CURSOR-STATIC As Long
= 3
Global Const SQL-ROWSET-SIZE-DEFAULT As Long
= 1
Global Const SQL-KEYSET-SIZE-DEFAULT As Long
= O
Global Const SQL-SC-NON-UNIQUE As Long = O
Global Const SQL-SC-TRY-UNIQUE As Long = 1
Global Const SQL-SC-UNIQUE As Long = 2
Global Const SQL-RD-OFF As Long = O
Global Const SQL-RD-ON As Long = 1
Global Const SQL-RD-DEFAULT As Long = SQL-RD-ON
Global Const SQL-UB-OFF As Long = O
Global Const SQL-UB-ON As Long = 1
Global Const SQL-UB-DEFAULT As Long
=
SQL-UB-ON
' Opciones para SQLSetConnectOption/SQLGetConnectOption
129
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-ACCESS-MODE As Long
= 101
Const SQL-AUTOCOMMIT As Long
= 102
Const SQL-LOGIN-TIMEOUT As Long = 103
Const SQL-OPT-TRACE As Long = 104
Const SQL-OPT-TRACEFILE As Long = 105
Const SQL-TRANSLATE-DLL As Long = 106
Const SQL-TRANSLATE-OPTION As Long
= 107
Const SQL-TXN-ISOLATION As Long = 108
Const SQL-CURRENT-QUALIFIER As Long = 109
Const SQL-CONNECT-OPT-DRVR-START As Long = 1000
I
Global Const SQL-ODBC-CURSORS As Long = 110
Global Const SQL-QUIET-MODE As Long = 111
Global Const SQL-PACKET-SIZE As Long= 112
Global Const SQL-CONN-OPT-MAX As Long
Global
Const
SQL-CONN OPT MIN
"
As
Long
=
SQL-PACKET-SIZE
=
SQLACCESS-MODE
Opciones de modo de acceso
1
Global Const SQL-MODE-READ WRITE As Long = O
Global Const SQL-MODE-READIONLY As Long = 1
Global ConstSQL-MODE-DEFAULT As Long= SQL-MODE-READ -WRITE
' Opciones para ejecución automática de transacciones
1
Global Const SQL-AUTOCOMMIT-OFF As Long
= O
Global Const SQL-AUTOCOMMIT-ON As Long = 1
Global Const SQL-AUTOCOMMIT-DEFAULT As
I
=
Long
SQL-AUTOCOMMIT-ON
Opciones para el tiempo límite de inicio de sesión
I
Global Const SQL-LOGIN-TIMEOUT-DEFAULT
As Long = 15
' Opciones de traza
1
Global
Global
Global
Global
Const SQL-OPT-TRACE-OFF As Long = O
Const SQL-OPT-TRACE-ON As Long = 1
Const SQL-OPT TRACE DEFAULT As Long= SQL-OPT TRACE-OFF
Const SQL-OPTITRACEZFILE-DEFAULT = "\\SQL.LOG"
1
' Opciones del cursor
I
Global Const SQL-CUR-USE IF NEEDED As Long= O
Global Const SQL-CUR USEIODBC As Long
= 1
Global Const SQL-CURIUSE-DRIVER As Long
= 2
Global ConstSQL-CUR-DEFAULT As Long= SQL-CUR-USE-DRIVER
' Tipos de columna y alcance en SQLSpecialColumns.
1
Global Const SQL-BEST-ROWID As Long
Global Const SQL-ROWVER As Long = 2
=
1
Global Const SQL-SCOPE-CURROW As Long = O
Global Const SQL-SCOPE-TRANSACTION As Long = 1
Global Const SQL-SCOPE-SESSION As Long = 2
I
I
Funciones de nivel 2
130
Valores SQLExtendedFetch "fFetchType"
I
Global
Global
Global
Global
Global
Global
Global
Const SQL-FETCH-NEXT As Long = 1
Const SQL-FETCH-FIRST As Long = 2
Const SQL-FETCH-LAST As Long = 3
Const SQL-FETCH-PRIOR As Long = 4
Const SQL-FETCH-ABSOLUTE As Long = 5
Const SQL-FETCH-RELATIVE As Long = 6
Const SQL-FETCH-BOOKMARK As Long = 8
' Valores SQLExtendedFetch "rgfRowStatus"
I
Global
Global
Global
Global
Const
Const
Const
Const
SQL-ROW-SUCCESS
SQL-ROW-DELETED
SQL-ROW-UPDATED
SQL
NOROW
- ROW
-
As Long = O
As Long = 1
As Long = 2
As Long
= 3
1
Global Const SQL-ROW-ADDED As Long
Global Const SQL-ROW-ERROR As Long
=
=
4
5
Definiciones para SQLForeignKeys (devuelto el
en conjunto de resultados)
I
Global Const SQL-CASCADE As Long = O
= 1
Global Const SQL RESTRICT As Long
Global Const SQLISET-NULL As Long= 2
' Definiciones para SQLProcedureColumns (devuelto
en el conjunto de resultados)
I
Global
Global
Global
Global
Const SQL-PARAM-TYPE-UNKNOWN As Long = O
Const SQL-PARAM-INPUT As Long = 1
Const SQL-PARAM-INPUT-OUTPUT As Long = 2
Const SQL-RESULT-COL As Long = 3
I
Global Const SQL-PARAM-OUTPUT As Long = 4
Definiciones para SQLStatistics
1
Global
Global
Global
Global
Const SQL-INDEX-UNIQUE As Long = O
Const SQL-INDEX-ALL As Long = 1
Const SQL-ENSURE As Long = 1
Const SQL-QUICK As Long = O
Definiciones para SQLStatistics (devuelto
en el conjunto de resultados)
I
Global
Global
Global
Global
Const SQL-TABLE-STAT As Long = O
Const SQL-INDEX-CLUSTERED As Long = 1
Const SQL-INDEX-HASHED As Long = 2
Const SQL-INDEX-OTHER As Long = 3
I
,
Procedimientos
Global Const SQL-PT-UNKNOWN As Long = O
Global Const SQL-PT.-PROCEDURE As Long = 1
Global Const SQL-PT-FUNCTION As Long = 2
' Procedimientos de columna
1
Global Const SQL-PC-UNKNOWN As Long
=
0
131
Global Const SQL-PC-NON-PSEUDO As Long = 1
Global Const SQL-PC-PSEUDO As Long = 2
' Definiciones para SQLSetPos
1
Global Const SQL-ENTIRE-ROWSET As Long
Global
Global
Global
Global
Global
=
O
Const SQL-POSITION As Long= O
Const SQL-REFRESH As Long= 1
Const SQL-UPDATE As Long = 2
Const SQL-DELETE As Long = 3
Const SQL-ADD As Long = 4
' Opciones de bloqueo
I
Global Const SQL-LOCK-NO-CHANGE As Long = O
Global Const SQL-LOCK-EXCLUSIVE As Long = 1
Global Const SQL-LOCK-UNLOCK As Long = 2
' Constantes globales de desacuerdo
I
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Global
Const SQL-DATABASE-NAME As Long = 16
Const SQL-FD-FETCH-PREV As Long = SQL-FD-FETCH-PRIOR
Const SQL-FETCH-PREV As Long = SQL-FETCH-PRIOR
= SQL CONCUR ROWVER
Const SQL CONCUR TIMESTAMP As Long
Const SQL-SCCO-OFT-TIMESTAMP As Long = S~L-SCCO~OPT
-ROWVER
=
SQL-CB
DELETE
Const SQL-CC
DELETE
As
Long
- . ConstSQL-CR-DELETE As Long = SQL CBIDELETE
Const SQL-CC-CLOSE As Long = SQL-CB-CLOSE
Const SQL-CR-CLOSE As Long = SQL-CB-CLOSE
Const SQL-CC-PRESERVE As Long= SQL-CB PRESERVE
Const SQL-CR-PRESERVE As Long = SQL-CB-PRESERVE
Const SQLFETCH-RESUME As Long = 7
Const SQL-SCROLL FORWARD-ONLY As Long
= O
Const SQL-SCROLL~KEYSET-DRIVENAs Long = -1
Const SQLISCROLL-DYNAMIC As Long
= -2
Const SQL-SCROLL-STATIC As Long = -3
#End If 'Win32
B
Conexion.bas: Código de las
funciones.
El archivo Conexionhas es la API de Visual Basic para conexi6n a bases de datos. El Listado 14
muestra el contenidodelarchivo
Conexionhas. Sepuedenapreciarlasdeclaracionesde
API, así como el c6digo fuente de las funciones
constantes y tipos de datos usados para esta
incluidas en la misma.
Listado 14. Listadodel módulo Conexion.bas.
I""""""""""""""""-
'Sección de declaraciones
1""""""""""""""""-
'Constantes de uso general
Global Const SQL MAX-ERROR-STRING
Global Const MAXIROWS= 100
Global Const BufferRet= 256
=
255
'Valor de Loop para DoEvents
Global ConstMAX-DOEVS = 30
'Valores de retorno de las funciones
= -2
Global Const HANDLE-INVALID0 As Long
Global Const ERROR-FUNC As Long
= -1
Global Const EXITO-FUNC As Long
= O
Global ConstEXIT0 FUNC-CON-INFO As Long = 1
Global Const SIGUE-EJECUTANDO As Long
= 2
= 99
Global Const NECESITA-DATOS As Long
Global Const NO
MAS DATOS As Long= 100
" _HAY
'Valores para AceptaNuloCol
Global Const SIN-NULOS As Long = O
Global Const CON-NULOS As Long
= 1
Global ConstNO-DETERM As Long
= 2
133
134
Private rc As Integer
Public Type BaseDatos
ENV As Long
ID As Long
NumTablas As Integer
NomTablas ( ) As String
End Type
Private Type RegistroSQL
NumRegAct As Integer
Datoscol() As String
End Type
Public Type ConsultaSQL
ID As Long
InstSQL As String
NumCols As Integer
NumRegs As Long
SQLTipoCol() As Integer
NomTipoCol() As String
AceptaNuloCol ( ) As Long
NomColO As String
Registro As RegistroSQL
End Type
I"""""""""""""""""""""
'Seccion de funciones
1"""""""""""
Public Sub CerrarInstrucSQL(CSQL As ConsultaSQL)
'Liberar todoslos handles y desconectar todo
If CSQL.ID <> SQL-NULL-HSTMT Then
rc = SQLFreeStmt(CSQL.ID, SQL-CLOSE) 'Libera el handle
de sentencia
Select Case rc
Case SQL-SUCCESS
Case SQL-SUCCESS-WITH-INFO
DescErrorODBC SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, True
Case SQL-ERROR
DescErrorODBC SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, True
Exit Sub
End Select
rc = SQLFreeStmt(CSQL.ID, SQL-DROP) 'Libera l o s recursos asignadosal handle
Select Case rc
Case SQL-SUCCESS
Case SQL SUCCESS-WITH-INFO
DescErrorODBC SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, True
Case SQL-ERROR
DescErrorODBC SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, True
Exit Sub
End Select
CSQL.ID = SQL-NULL-HSTMT 'Asignar el valor nulo al handle de instruccian
End I f
End Sub
Public Function EjecutarSQL(BD As BaseDatos, ByVal
SQL$, ByVal MostrarError,CadErrorS) As Integer
Dim Cr As String
Cr = Chr(l3) & Chr(l0)
Dim lrc As Integer
135
Dim MsgActual As String
Dim hstmtlocal As Long
lrc = SQL-SUCCESS
CadError =
MsgActual =
"I'
"I'
'Inicializa el handle
de instrucción para cada operación
de escritura
hstmtlocal = SQL-NULL-HSTMT 'Asigna un valor nulo al handle
de instrucción
'Obtiene un nuevo handle de instrucción
rc = SQLAllocStmt(BD.ID, hstmtlocal)
'Prueba los casos en los que puede caer rc
Select Case rc
Case SQL-SUCCESS
lrc = rc
Case SQL SUCCESS WITH-INFO
CadError = DescErrorODBC (SQL-NULL-HENV, SQL-NULL-HDBC, hstmtlocal, MostrarError)
lrc = rc
Case SQL-ERROR
CadError = DescErrorODBC(SQL-NULL-HENV, SQL- NULL- HDBC, hstmtlocal,
MostrarError)
lrc = rc
EjecutarSQL = lrc
Exit Function
End Select
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
'Remite el Query
rc = SQLExecDirect (hstmtlocal, SQL, Len ) (SQL)
Select Case rc
Case SQL-SUCCESS
'No lleva lrc = rc para no sobreescribir un SQL-SUCCESS-WITH-INFO
Case SQL SUCCESS-WITH-INFO
MsgAccual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, hstmtlocal,MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL-NEED-DATA
lrc = rc
EjecutarSQL = lrc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL_NULL-HENV, SQL-NULL -HDBC, hstmtlocal, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
EjecutarSQL = lrc
Exit Function
End Select
I*********************************************
'Liberar todoslos handles y desconectar todo
hstmtlocal <> SQL-NULL-HSTMT Then
rc = SQLFreeStmt(hstmtloca1, SQL-CLOSE) 'Libera el handle de sentencia
Select Case rc
Case SQL-SUCCESS
un
'No lleva lrc= rc para no sobreescribir SQL-SUCCESS-WITH-INFO
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL_NULL-HENV, SQL-NULL-HDBC, hstmtlocal, MostrarError)
If
136
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL-ERROR
MsgActual = DescErrorODBC(SQLJULL-HENV,
MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
EjecutarSQL = lrc
Exit Function
End Select
'Libera los recursos asignados al handle
rc = SQLFreeStmt(hstmtloca1, SQL-DROP)
Select Case rc
Case SQL-SUCCESS
'No lleva lrc= rc para no sobreescribir
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV,
MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV,
MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
EjecutarSQL = lrc
Exit Function
End Select
hstmtlocal = SQL-NULL-HSTMT 'Asignar el valor
End If
EjecutarSQL
=
SQL-NULL-HDBC, hstmtlocal,
-
unSQL-SUCCESS-WITH-INFO
SQL-NULL-HDBC, hstmtlocal, -
SQL-NULL-HDBC, hstmtlocal,
-
nulo al handle
de instrucción
lrc
End Function
Public Function ErroresNativos(ByVa1 MsgErrorS) As String
Dim ErrNat As String
Dim PosCad As Integer, Inicio As Integer, Longitud As Integer
ErrNat = " "
Inicio = 1
If MsgError <> '"' Then
Do
PosCad = InStr(Inici0, MsgError, "Error nativo:
", O )
I f PosCad > O Then
Inicio = PosCad + 1 4
PosCad = InStr (Inicio, MsgError,
" "r
0)
Longitud = PosCad - Inicio
ErrNat = ErrNat + " / " f Mid(MsgError, Inicio, Longitud)
End If
Loop Until PosCad= O
End If
ErroresNativos = ErrNat
End Function
Public Function DescErrorODBC(ByVa1 rhenv&, ByVal rhdbc&, ByVal rhstmt&,
ByVal MostrarErr) As String
Const LngBuffSalida= SQL-MAX-ERROR-STRING
= "Error del controlador ODBC"
Const TitError As String
137
Dim Cr$
Dim CrLfS
Cr$ = Chr$ (13)
CrLf$ = ChrS(13) & ChrS(10)
Dim CadDescCorta As String* 16
Dim CadDescExt As String
* LngBuffSalida
Dim LngDescrip As Integer
Dim ErrNativo As Long
Dim lrc As Integer
CadDescCorta = String(l6, O)
CadDescExt = String(LngBuffSalida, O)
Dim lhenv As Long, lhdbc As Long, lhstmt As Long
Dim MsgActualAs String
Dim CadResultErr As String
MsgActual =
CadResultErr =
For L = 1 To 3
I"'
'"I
Select Case L
Case 1
lhenv = SQL-NULL-HENV
lhdbc = SQL-NULL-HDBC
lhstmt = rhstmt
Case 2
lhenv = SQL-NULL-HENV
lhdbc = rhdbc
lhstmt = SQL-NULL-HSTMT
Case 3
lhenv = rhenv
lhdbc = SQL-NULL HDBC
lhstmt = SQL-NULZ-HSTMT
End Select
'Obtener todosl o s errores de el buffer de errores
Do
lrc = SQLError(lhenv, lhdbc, lhstmt, CadDescCorta, ErrNativo, CadDescExt,
LngBuffSalida, LngDescrip)
If lrc = SQL SUCCESS Or lrc= SQL-SUCCESS-WITH-INFO Then
If LngDescrip = O Then
MsgActual = "Error -- No hay información disponible"
If MostrarErr Then MsgBox MsgActual, vbExclamation, TitError
CadResultErr = CadResultErr & CrLf & MsgActual
Else
If ErrNativo= O Then
MsgActual = Left$(CadDescExt, LngDescrip)
I f MostrarErr Then MsgBox MsgActual, vbExclamation, TitError
CadResultErr = CadResultErr & CrLf & MsgActual
Else
MsgActual = Left$(CadDescExt, LngDescrip)& Cr
MsgActual = MsgActual & "Error nativo: " & ErrNativo &
''
If MostrarErrThen MsgBox MsgActual, vbcritical, TitError
CadResultErr = CadResultErr & CrLf & MsgActual
End If
End If
End I f
Loop Until lrc<> SQL-SUCCESS
'I
Next L
DescErrorODBC
End Function
=
CadResultErr
138
Public Sub DesconectarBD(BD
As BaseDatos)
I f BD.ID <> SQL NULL-HDBC Then
(BD. ID)
'Desconecta
de la
BD
rc = SQLDiscGnnect
Select Case rc
Case SQL-SUCCESS
Case SQL-SUCCESS-WITH-INFO
DescErrorODBC SQL-NULL-HENV, BD.ID, SQL-NULL-HSTMT, True
Case SQL-ERROR
DescErrorODBC SQL-NULL-HENV, BD.ID, SQL-NULL-HSTMT, True
Exit Sub
End Select
rc = SQLFreeConnect(BD.ID) 'Libera el handlede conexión y los recursos
Select Case rc
Case SQL-SUCCESS
Case SQL SUCCESS-WITH-INFO
DescErrorODBC SQL-NULL-HENV, BD. ID, SQL-NULL-HSTMT, True
Case SQL-ERROR
DescErrorODBC SQL-NULL-HENV, BD.ID, SQL- NULL-HSTMT, True
Exit Sub
End Select
BD.ID = SQL-NULL-HDBC 'Asignar
el valor nulo al handle de conexión
End If
If BD.ENV <> SQL-NULL-HENV Then
(BD.
ENV)
'Libera
el
handler
de ambiente
rc = SQLFreeEnv
Select Case rc
Case SQL SUCCESS
Case SQL-SUCCESS-WITH-INFO
DescEgrorODBC BD.ENV, SQL
HDBC, -SQL
NULL-HSTMT, True
- NULL
Case SQL ERROR
DescErrorODBC BD.ENV, SQL-NULL-HDBC, SQL- NULL-HSTMT, True
Exit S u b
End Select
de ambiente
BD.ENV = SQL-NULL-HENV 'Asignar el valor nulo al handle
End If
End Sub
Public Function ConectarBD (ByVal DSN$, ByVal UIDS, ByVal
PWD$, BD As BaseDatos,ByVal MostrarErr, CadErroresS) As Integer
'NOTA: Pasar por referencia una estructura en la que se devuelvan
los datos
'relacionados con la BD, esto es Tablas, Driver,etc.
'Realizar las conexiones necesarias a la BD
'y todas las inicializaciones requeridas
Dim Conecta As String
* 255
Dim ConexionAbierta As String
Dim LongitudCA As Integer
CadErrores =
'Obtiene un handle para el ambiente
I f BD.ENV <> SQL-NULL-HENV Then
rc = SQLFreeEnv(BD.ENV)
BD.ENV = SQL-NULL-HENV
End I f
rc = SQLAllocEnv(BD.ENV)
I"'
'Inicializa el handlede conexión
If BD.ID <> SQL NULL-HDBC Then
'Desconecta de la BD
ID)
rc = SQLDisconnect (BD.
'Libera la conexión
rc = SQLFreeConnect(BD.ID)
BD.ID = SQL-NULL-HDBC
139
End If
rc = SQLAllocConnect(BD-ENV,BD.ID)
'Establecer las opciones de conexión
'rc = SQLSetConnectOption(BD.ID, SQL-ACCESS-MODE, SQL MODE-READ-WRITE)
rc = SQLSetConnectOption(BD.ID, SQL-ODBC-CURSORS, SQLICUR USE-ODBC)
' rc = SQLSetConnectOption (BD. SQL-TXN-ISOLATION,
ID,
SQL T?N REPEATABLE-READ)
"
'BD.ID
rc
=
=
hdbc
SQLConnect
(BD.
ID, DSN, Len (DSN1 ,
UID, Len(UID), PWD, Len (PWD)
)
'Checar la info del error
'rc puede serSQL-SUCCESS-WITH-INFO ' o SQL-ERROR y en estos casos hay
información
Select Case rc
Case SQL-SUCCESS
'BD.ID = hdbc
Case SQL SUCCESS- WITH
- INFO
'BD.I f = hdbc
CadErrores = DescErrorODBC(BD.ENV, BD.ID, SQL-NULL-HSTMT, MostrarErr)
Case SQL-ERROR
'BD.ID = SQL-NULL-HDBC
CadErrores = DescErrorODBC(BD.ENV, BD.ID, SQL
-NULL-HSTMT, MostrarErr)
End Select
'Obtiene información de la conexión
ConectarBD
=
rc
End Function
Public Function ConectarBD2(ByVal Cadcon$, BD As BaseDatos, ByVal MostrarErr,
CadErroresS) As Integer
'NOTA: Pasar por referencia una estructura en la se
que
devuelvan los datos
'relacionados con l a BD, esto es Tablas, Driver, etc.
'Realizar las conexiones necesarias laa BD
'y todas las inicializaciones requeridas
Dim Conecta As String
Dim ConexionAbierta As String * 255
Dim LongitudCA As Integer
CadErrores = " "
'Obtiene un handle para el ambiente
If BD.ENV <> SQL-NULL-HENV Then
rc = SQLFreeEnv(BD.ENV)
BD.ENV = SQL-NULL-HENV
End If
rc = SQLAllocEnv(BD.ENV)
'Inicializa el handlede conexión
If BD.ID <> SQL NULL HDBC Then
rc = SQLDisc&nect(BD. ID)
'Desconecta de la BD
la conexión
rc = SQLFreeConnect(BD.ID) 'Libera
BD.ID = SQL-NULL-HDBC
End If
rc = SQLAllocConnect(BD.ENV, BD.ID)
'Establecer las opciones
de conexión
rc = SQLSetConnectOption(BD.ID, SQL ACCESS MODE, SQLMODE-READ WRITE)
(BD.
ID, SQL-ODBC
-CURSORS,
SQz-CUR-USE-~DBC)
rc = SQLSetConnectOption
140
'rc
=
SQLSetConnectOption(BD.ID, SQL-TXN-ISOLATION, SQL-TXN-REPEATABLE-READ)
'BD.ID
=
hdbc
'rc = SQLConnect(BD.ID, DSN,Len(DSN), UID, Len(UID), PWD, Len(PWD))
, ConexionAbierta, 255, rc = SQLDriverConnect(BD.ID, hWnd, CadCon, Len (CadCon)
LongitudCA, SQL-DRIVER-COMPLETE)
'Checar lainfo del error
'rc puedeser SQL-SUCCESS-WITH-INFO o SQL-ERROR y en estos casos hay
'información
Select Case rc
Case SQL-SUCCESS
'BD.ID = hdbc
Case SQL SUCCESS-WITH-INFO
'BD.I< = hdbc
CadErrores = DescErrorODBC(BD.ENV, BD.ID, SQL-NULL-HSTMT, MostrarErr)
Case SQL-ERROR
'BD.ID = SQL-NULL-HDBC
CadErrores = DescErrorODBC(BD.ENV, BD.ID, SQL-NULL-HSTMT, MostrarErr)
End Select
'Obtiene informaciónde la conexión
ConectarBD2
=
rc
End Function
Public Function HacerConsultaSQL(BD As BaseDatos, ByVal SQL$,
CSQL As ConsultaSQL, ByVal MostrarError, CadErrorS) As Integer
Dim CrAs String
Cr = Chr (13) & Chr (10)
Dim sValor As String* BufferRet
Dim sSQL As String
* BufferRet
Dim lValor AsLong, iValor As Integer, larg2
As Long
Dim TotalCols As Integer, I As Integer
Dim lrc As Integer
Dim MsgActualAs String
lrc = SQL-SUCCESS
CadError =
MsgActual =
'Inicializa el handle de instrucción para cada consulta
If CSQL.ID <> SQL NULL-HSTMT Then
'Cierra la consulta actual pero
no libera el handle
ID, SQL-CLOSE)
rc = SQLFreeStmt (CSQL.
'Libera el handlede instrucción yS U S recursos
rc = SQLFreeStmt (CSQL. SQL-DROP)
ID,
CSQL.ID = SQL-NULL-HSTMT 'Asigna un valor nulo al handle de instrucción
End If
'Obtiene un nuevo handle de instrucción
rc = SQLAllocStmt(BD.ID, CSQL.ID)
'Prueba l o s casos en l o s que puede caer rc
Select Case rc
Case SQL-SUCCESS
lrc = rc
Case SQL-SUCCESS-WITH-INFO
-NULL-HDBC, CSQL
CadError = DescErrorODBC(SQL-NULL-HENV, SQL
MostrarError)
lrc = rc
Case SQL-ERROR
CadError = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL
I"'
I"'
141
MostrarError)
lrc = rc
HacerConsultaSQL
Exit Function
End Select
lrc
=
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
'Ajusta las opciones de el handle
de instrucción
rc = SQLSetStmtOption(CSQL.ID, SQL- CURSOR
- TYPE,SQL-CURSOR-STATIC)
Select Case rc
Case SQL-SUCCESS
'No lleva lrc = rc para no sobreescribir unSQL-SUCCESS-WITH-INFO
Case SQL SUCCESS-WITH-INFO
MsgAcrual = DescErrorODBC (SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL_NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
HacerConsultaSQL = lrc
Exit Function
End Select
rc = SQLSetStmtOption(CSQL.ID, SQL-ROWSET-SIZE, MAX-ROWS)
Select Case rc
Case SQL-SUCCESS
'No lleva lrc= rc para no sobreescribir un SQL-SUCCESS-WITH-INFO
Case SQL SUCCESS WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL. ID,
MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL -HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
HacerConsultaSQL = lrc
Exit Function
End Select
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
'Asigna el valor del handle al ID de la Consulta y la instrucción SQL
'CSQL.ID = hstmt
CSQL.InstSQL = SQL
I*********************************************
'Remite el Query
O)
'sSQL = String$ (BufferRet,
'sSQL = SQL
ID, SQL, Len (SQL)
)
rc = SQLExecDirect (CSQL.
Select Case rc
Case SQL-SUCCESS
'No lleva lrc= rc para no sobreescribir un SQL-SUCCESS-WITH-INFO
Case SQL SUCCESS-WITHINFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL. ID,
MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL
-NEED-DATA
lrc = rc
HacerConsultaSQL = lrc
Exit Function
142
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL_NULL-HENV, SQL-NULL-HDBC, CSQL-IDr MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
HacerConsultaSQL = lrc
Exit Function
End Select
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
'Obtiene el número de columnas
de el resultadode el query
rc = SQLNumResultCols(CSQL.ID, TotalCols)
Select Case rc
Case SQL-SUCCESS
'No lleva lrc= rc para no sobreescribir
u11 SQL-SUCCESS-WITH-INFO
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQLeIDr MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL-STILL-EXECUTING
lrc = rc
HacerConsultaSQL = Irc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENVr SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
HacerConsultaSQL = lrc
Exit Function
End Select
CSQL.NumCols = TotalCols
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
'Obtiene el número de renglones de la consulta
CSQL.NumRegs = O
Do
ID)
rc = SQLFetch (CSQL.
Select Case rc
Case SQL-SUCCESS
'No lleva lrc= rc para no sobreescribir unSQL-SUCCESS-WITH-INFO
CSQL.NumRegs = CSQL.NumRegs + 1
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENVr SQL-NULL-HDBC, CSQLeIDr
MostrarError)
CadError = CadError & Cr & MsgACtual
lrc = rc
CSQL.NumRegs = CSQL.NumRegs + 1
Case SQL-NO-DATA-FOUND
Case SQL-STILL-EXECUTING
lrc = rc
HacerConsultaSQL = lrc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL_HENV, SQL-NULL-HDBC, CSQL.IDr MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
HacerConsultaSQL = lrc
Exit Function
End Select
Loop Until rc = SQL-NO-DATA-FOUND
'Pone el cursor nuevamente enel primer renglón
_"
.
143
rc = RepUltimaConsulta(CSQL, MostrarError, MsgActual)
Select Case rc
Case SQL SUCCESS
'No lieva Irc= KC para no sobreescribir unSQL-SUCCESS-WITH-INFO
Case SQL-SUCCESS-WITH-INFO
CadErr = CadErr & Cr & MsgActual
lrc = rc
Case SQL-ERROR
CadErr = CadErr & Cr & MsgActual
lrc = rc
HacerConsultaSQL = lrc
Exit Function
Case SQL-INVALID-HANDLE
CadErr = CadErr & Cr & MsgActual
lrc = rc
HacerConsultaSQL = lrc
Exit Function
End Select
....................................................................
'Recupera información variadade las columnas
ReDim CSQL.NomCol(1To TotalCols) As String
ReDim CSQL.NomTipoCol(1To TotalCols) As String
ReDim CSQL.SQLTipoCol(1To TotalCols) As Integer
ReDim CSQL.AceptaNuloCol(1To TotalCols) As Long
For I = 1 To TotalCols
'Recupera los encabezados de las tablas y los asigna al
'array de Nombres de Columnas
O)
sValor = String$ (BufferRet,
iValor = O
rc = SQLColAttributesString(CSQL.ID, I, SQL-COLUMN-LABEL, sValor, 255, ivalor, larg2)
Select Case rc
Case SQL-SUCCESS
'No lleva lrc= rc para no sobreescribir un SQL-SUCCESS-WITH-INFO
CSQL.NomCo1(I) = Left$ (sValor, ivalor)
Case SQL-SUCCESS-WITH-INFO
SQL-NULL-HDBC, CSQL.ID, MsgActual = DescErrorODBC(SQL- NULL
- HENV,
MostrarError)
CadError = CadError & MsgActual
lrc = rc
CSQL.NomCo1 (I) = Left$ (sValor, ivalor)
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & MsgActual
lrc = rc
HacerConsultaSQL = lrc
Exit Function
End Select
'Recupera los nombres de los tipos de datosde cada una de las columnas
sValor = String$(BufferRet, O)
iValor = O
Select Case rc
Case SQL-SUCCESS
'No lleva lrc= rc para no sobreescribir unSQL-SUCCESS-WITH-INFO
CSQL.NomTipoCo1 (I) = Left$ (sValor, iValor)
Case SQL SUCCESS WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL. ID,
MostrarError)
CadError = CadError & MsgActual
144
lrc = rc
~ ~ ~ ~ . N o m T i p(I)
o C o= lLeft$
(svalor,
iValor)
MostrarError)
CadError = CadError & MsgActual
lrc = rc
HacerConsultaSQL = lrc
Exit Function
End Select
'Recupera l o s tipos de datos SQL de cada una de las columnas
sValor = String$ (BufferRet,
0)
larg2)
Select Case rc
Case SQL-SUCCESS
'No lleva lrc= rc para no sobreescribir unSQL-SUCCESS-WITH-INFO
CSQL. SQLTipoCol
(I) = larg2
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & MsgActual
lrc = rc
CSQL. SQLTipoCol
(I) = larg2
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & MsgActual
lrc = rc
HacerConsultaSQL = 1rc
Exit Function
End Select
'Determina las columnas que aceptan nulos
sValor = String$ (BufferRet,
O)
iValor = O
rc = SQLColAttributes(CSQL.ID, I, SQL- COLUMN-NULLABLE, SValor, 255, ivalor, larg2)
Select Case rc
Case SQL-SUCCESS
'NO lleva lrc = rc para no sobreescribir
un SQL-SUCCESS-WITH-INFO
CSQL.AceptaNuloCo1(I) = larg2
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL-ID, MostrarError)
CadError = CadError & MsgActual
lrc = rc
CSQL .AceptaNuloCol ( I ) = larg2
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & MsgActual
lrc = rc
HacerConsultaSQL = lrc
Exit Function
End Select
Next I
'Prepara los subparámetros de registro de la Consulta
CSQL.Registro.NumRegAct = 0
ReDirn CSQL.Registro.DatosCol(1 To TotalCols) AS String
HacerConsultaSQL
=
lrc
145
End Function
Public Function HacerEscrituraSQL(BD As BaseDatos, ByVal SQL$,
CSQL As ConsultaSQL, ByVal MostrarError, CadErrorS)
As Integer
Dim Cr As String
Cr = Chr (13) & Chr (10)
Dim lrc As Integer
Dim MsgActual As String
'Utilizar SQLPrepare, SQLBindParameter, SQLExec, SQLRowCount.
'Si se repite regresar a SQLExec
y por último SQLTransac
lrc = SQL-SUCCESS
CadError =
MsgActual = " "
'Inicializa el handlede instrucción para cada operación
de escritura
If CSQL.ID <> SQL NULL-HSTMT Then
'Cierra la consulta actual pero
no libera el handle
rc = SQLFreeStmt(CSQL.ID, SQL CLOSE)
'Libera el handlede instrucción y sus recursos
ID,
rc = SQLFreeStmt (CSQL. SQL-DROP)
de instrucción
CSQL.ID = SQL-NULL-HSTMT 'Asigna un valor nulo al handle
End If
'Obtiene un nuevo handle de instrucción
rc = SQLAllocStmt (BD. ID, CSQL. ID)
'Prueba los casos en los que puede caerrc
Select Case rc
Case SQL-SUCCESS
lrc = rc
Case SQL SUCCESS-WITH-INFO
CadError = DescErrorODBC (SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
lrc = rc
Case SQL-ERROR
CadError = DescErrorODBC(SQL_NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
lrc = rc
HacerEscrituraSQL = lrc
Exit Function
End Select
"I'
CSQL.InstSQL
=
SQL
I*********************************************
'Remite el Query
rc = SQLExecDirect (CSQL.
I D , SQL, Len(SQL))
Select Case rc
Case SQL SUCCESS
'No lleva lrc= rc para no sobreescribir un SQL-SUCCESS-WITH-INFO
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL_NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL-NEED-DATA
lrc = rc
HacerEscrituraSQL = lrc
Exit Function
Case SQL-ERROR
146
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL- NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
HacerEscrituraSQL = Irc
Exit Function
End Select
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
'Obtiene el número de parámetros implicados
CSQL.NumCols = 0
rc = SQLNumParams(CSQL.ID, CSQL.NumCols)
Select Case rc
Case SQL-SUCCESS
'No lleva lrc = rc para no sobreescribir
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV,
MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV,
MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
HacerEscrituraSQL = lrc
Exit Function
End Select
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
en la operación de escritura
un SQL-SUCCESS-WITH-INFO
SQL- NULL-HDBC, CSQL.ID,
-
SQL-NULL-HDBC, CSQL.ID, -
.
.
.
.
.
.
.
.
.
.
.
.
'Obtiene el número de renglones afectados por
la escritura
CSQL.NumRegs = O
rc = SQLRowCount(CSQL.ID, CSQL.NumRegs)
Select Case rc
Case SQL-SUCCESS
'No lleva lrc = rc para no sobreescribir un SQL-SUCCESS-WITH-INFO
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
HacerEscrituraSQL = lrc
Exit Function
End Select
'prepara los subparámetros de registro
de la consulta
CSQL.Registro.NumRegAct = 0
ReDim cSQL.Registro.DatosCol(1 To CSQL.NumCols) As String
HacerEscrituraSQL
=
End Function
Dim Cr As String
1rc
147
Cr = Chr(l3) & Chr(l0)
Dim lrc As Integer
Dim MsgActual As String
lrc = SQL-SUCCESS
CadError = " "
MsgActual =
'Inicializa el handle de instrucción para cada operación
de escritura
If CSQL.ID <> SQL NULL HSTMT Then
'Cierra la consulta-actual pero no libera el handle
rc = SQLFreeStmt(CSQL.ID, SQL CLOSE)
'Libera el handlede instrucción y sus recursos
rc = SQLFreeStmt (CSQL. SQL-DROP)
ID,
CSQL.ID = SQL-NULL-HSTMT 'Asigna un valor nuloal handle de instrucción
End If
'Obtiene un nuevo handlede instrucción
rc = SQLAllocStmt(BD.ID, CSQL.ID)
'Prueba los casosen los que puede caerrc
Select Case rc
Case
SQL
-SUCCESS
lrc = rc
Case SQL SUCCESS-WITH-INFO
CadError = DescErrorODBC (SQL-NULL-HENV, SQL- NULL
- HDBC, CSQL. - ID,
MostrarError)
lrc = rc
Case SQL-ERROR
CadError = DescErrorODBC (SQL
-NULL-HENV,
SQL-NULL- HDBC,CSQL.ID, MostrarError)
lrc = rc
HacerEscDirectaSQL = lrc
Exit Function
End Select
I"'
CSQL.InstSQL
.
.
.
.
.
.
.
.
.
.
.
.
.
=
SQL
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
'Remite el Query
rc = SQLExecDirect (CSQL.ID, SQL, Len(SQL))
Select Case rc
Case SQL-SUCCESS
'No lleva lrc = rc para no sobreescribir unSQL-SUCCESS-WITH-INFO
Case SQL SUCCESS-WITH-INFO
MsgActual = DescErrorODBC (SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQLNEED-DATA
lrc = rc
HacerEscDirectaSQL = lrc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL_NULL-HENV, SQL-NULL- HDBC, CSQL.ID,MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
HacerEscDirectaSQL = lrc
Exit Function
End Select
........................................................................
'Obtiene el número de parámetros implicados enla operación de escritura
CSQL.NumCols = O
rc = SQLNumParams(CSQL.ID, CSQL.NumCols)
Select Case rc
Case SQL-SUCCESS
'No lleva lrc= rc para no sobreescribir
un SQL-SUCCESS-WITH-INFO
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
HacerEscDirectaSQL = lrc
Exit Function
End Select
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
'Obtiene el nímerode renglones afectados por
la escritura
CSQL.NumRegs = O
rc = SQLRowCount (CSQL.
ID, CSQL.NumRegs
Select Case rc
Case SQL SUCCESS
'No lleva lrc= rc para no sobreescribir unSQL-SUCCESS-WITH-INFO
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarError)
CadError = CadError & Cr & MsgActual
lrc = rc
HacerEscDirectaSQL = Irc
Exit Function
End Select
'Prepara los subparámetros de registro de la consulta
CSQL.Registro.NumRegAct= 0
ReDim CSQL.Registro.DatosCol(CSQL.NumCo1s) As String
HacerEscDirectaSQL
=
lrc
End Function
Public Function PriRegConsultaSQL(CSQL
As ConsultaSQL, ByVal MostrarErr,
CadErrS) As Integer
Dim
Dim
Dim
Dim
Dim
Dim
I As Integer
* BufferRet
sValor As String
lValor As Long
DatoCol As String
MsgActual As String
lrc As Integer
CadErr
=
"I'
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
'Regresa al iniciode el registro
rc = RepUltimaConsulta (CSQL, MostrarErr,
Select Case rc
CadErr)
149
Case SQL-SUCCESS
lrc = rc
Case SQL-SUCCESS-WITH-INFO
lrc = rc
Case SQL-ERROR
lrc = rc
PriRegConsultaSQL = lrc
Exit Function
Case SQL INVALID HANDLE
PriReTConsultaSQL = SQL-ERROR
Exit Function
End Select
'Obtiene un renglón de el resultado del Query
ID)
rc = SQLFetch (CSQL.
'Prueba todoslos posibles resultadosde rc
Select Case rc
Case SQL-SUCCESS
lrc = rc
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL_NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & MsgActual
lrc = rc
Case SQL-NO-DATA-FOUND
lrc = rc
PriRegConsultaSQL = lrc
Exit Function
Case SQL-INVALID HANDLE
MsgActual = "Handle inválido"
CadErr = CadErr & Cr & MsgActual
lrc = rc
PriRegConsultaSQL = lrc
Exit Function
Case SQL- STILL-EXECUTING
lrc = rc
PriRegConsultaSQL = lrc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL - HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & MsgActual
lrc = rc
PriRegConsultaSQL = lrc
Exit Function
End Select
I f rc = SQL-SUCCESS Or rc
= SQL-SUCCESS-WITH -INFO
Then
CSQL.Registro.NumRegAct = 1
'Asignar un dato a cada elementode RSQL
For I = 1 To CSQL.NumCols
sValor = String$(BufferRet, O)
lValor = O
rc = SQLGetData (CSQL.ID, I, SQL-C-CHAR, sValor, BufferRet, 1Valor)
Select Case rc
Case SQL-SUCCESS
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & MsgActual
lrc = rc
Case SQL-NO-DATA-FOUND
lrc = rc
PriRegConsultaSQL = lrc
150
Exit Function
Case SQL-STILL-EXECUTING
lrc = rc
PriRegConsultaSQL = lrc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & MsgActual
lrc = rc
PriRegConsultaSQL = lrc
Exit Function
End Select
'Verificar datos nulos
If lValor < 1 Then 'Dato con valor nulo
DatoCol =
valor
algún
con
'Dato
Else
DatoCol = Left$ (sValor, 1Valor)
End If
CSQL.Registro.DatosCol(1)= DatoCol
Next I
End If
"I'
End Function
Private Function RepUltimaConsulta(CSQL As ConsultaSQL, ByVal MostrarErr,
CadErr$) As Integer
Dim
Dim
Dim
Cr =
lrc As Integer
MsgActual As String
Cr As String
Chr(l3) & Chr(l0)
lrc = SQL-SUCCESS
CadErr = " "
MsgActual = " "
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
'Inicializa el handle de instrucción perono lo libera
'Cierra la consulta actual pero
no libera el handle
rc = SQLFreeStmt(CSQL.ID, SQL-CLOSE)
Select Case rc
Case SQL-SUCCESS
lrc = rc
Case SQL SUCCESS-WITH-INFO
CadErr = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MOstrarErr)
lrc = rc
Case SQL-ERROR
CadErr = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
lrc = rc
RepUltimaConsulta = lrc
Exit Function
Case SQL INVALID-HANDLE
CadErr = "Handle inválido"
RepUltimaConsulta = SQL-ERROR
Exit Function
End Select
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
'Ajusta las opcionesde el handle de instrucción
rc = SQLSetStmtOption(CSQL.ID, SQL- CURSOR-TYPE, SQL- CURSOR-STATIC)
Select Case rc
Case SQL-SUCCESS
'NO lleva lrc = rc para no sobreescribir un
SQL-SUCCESSWITH-INFO
151
Case SQL SUCCESS-WITH-INFO
MsgActual = DescErrorODBC (SQL-NULL-HENV, SQL- NULL
-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
RepUltimaConsulta = lrc
Exit Function
End Select
rc = SQLSetStmtOption(CSQL.ID, SQL-ROWSET-SIZE, MAX-ROWS)
Select Case rc
Case SQL-SUCCESS
'No lleva lrc= rc para no sobreescribir un SQL-SUCCESS-WITH-INFO
Case SQL SUCCESS WITH INFO
MsgAccual = DgscErrorODBC (SQL-NULL-HENV, SQL- NULL
-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
RepUltimaConsulta = lrc
Exit Function
End Select
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
'Se remite el mismo query otra ves. Esta
es una forma de mover
'al principioal cursor
rc = SQLExecDirect(CSQL.ID, CSQL.InstSQL, Len(CSQL.1nstSQL))
Select Case rc
Case SQL-SUCCESS
'No lleva lrc = rc para no sobreescribir un SQL-SUCCESS-WITH-INFO
Case SQL SUCCESS WITH INFO
MsgAccual = DescErrorODBC (SQL-NULL-HENV, SQL- NULL
ID, - HDBC, CSQL.
MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
Case SQL-NEED-DATA
lrc = rc
RepUltimaConsulta = lrc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL- NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
RepUltimaConsulta = lrc
Exit Function
End Select
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
'Reinicializa los valores
de registro de la consulta
CSQL.Registro.NumRegAct = O
RepUltimaConsulta
End Function
=
lrc
152
Public Function SigRegConsultaSQL(CSQL As ConsultaSQL, ByVal MostrarErr,
CadErr$) As Integer
Dim Cr As String
Cr = Chr(l3) & Chr(l0)
Dim I As Integer
Dim sValor As String
* BufferRet
Dim lValor As Long
Dim DatoCol As String
Dim MsgActual As String
Dim lrc As Integer
CadErr =
'Obtiene un renglón de el resultado del Query
rc = SQLFetch (CSQL. ID)
'Prueba todos l o s posibles resultados de rc
Select Case rc
Case SQL-SUCCESS
lrc = rc
Case SQL-SUCCESS-WITH INFO
MsgActual = DescErgorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
Case SQL-NO-DATA-FOUND
Irc = rc
SigRegConsultaSQL = lrc
Exit Function
Case SQL INVALID-HANDLE
MsgAccual = "Handle inválido"
CadErr = CadErr & Cr.& MsgActual
lrc = rc
SigRegConsultaSQL = lrc
Exit Function
Case
SQL
-STILL-EXECUTING
lrc = rc
SigRegConsultaSQL = lrc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL- HDBC, CSQL.ID,MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
SigRegConsultaSQL = lrc
Exit Function
End Select
If rc = SQL-SUCCESS Or rc = SQL-SUCCESS-WITH-INFO Then
CSQL.Registro.NumRegAct = CSQL.Registro.NumRegAct + 1
'Asignar un dato a cada elemento de RSQL
For I = 1 To CSQL.NumCols
O)
sValor = String$ (BufferRet,
lvalor = O
rc = SQLGetData(CSQL.ID, I, SQL-C-CHAR, ?,Valor, BufferRet, 1Valor)
Select Case rc
Case SQL-SUCCESS
Case SQL SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
Case SQL-NO-DATA-FOUND
lrc = rc
I"'
153
SigRegConsultaSQL = lrc
Exit Function
Case SQL-STILL-EXECUTING
lrc = rc
SigRegConsultaSQL = lrc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL_HENV,
MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
SigRegConsultaSQL = lrc
Exit Function
End Select
'Verificar datosnulos
If lValor < 1 Then 'Dato con valor nulo
DatoCol = " "
valor
algún
con
'Dato
Else
DatoCol = Left$ (sValor, 1Valor)
End If
CSQL.Registro.DatosCol(1)= DatoCol
Next I
End If
SQL-NULL-HDBC, CSQL.ID, -
End Function
Public Function UltRegConsultaSQL(CSQL As ConsultaSQL,
ByVal MostrarErr, CadErrS) As Integer
Dim Cr As String
Cr = Chr(l3) & Chr(l0)
Dim I As Integer
Dim sValor As String* BufferRet
Dim lValor As Long
Dim DatoCol As String
Dim MsgActual As String
Dim lrc As Integer
lrc = SQL-SUCCESS
CadErr = " "
'Prueba si ya está en el último registro. De ser así simplemente sale
If CSQL.Registro.NumRegAct= CSQL.NumRegs Then
UltRegConsultaSQL = SQL-SUCCESS
Exit Function
End If
'Realiza el Fetch hasta llegar al último registro
Do
rc = SQLFetch (CSQL.
ID)
Select Case rc
Case SQL-SUCCESS
'No lleva Irc = rc para no sobreescribir un SQL-SUCCESS-WITH-INFO
CSQL.Registro.NumRegAct = CSQL.Registro.NumRegAct + 1
Case SQL SUCCESS WITH
INFO
CSQL. Registro
rNumR<gAct = CSQL. Registro. NumRegAct
+ 1
MsgActual = DescErrorODBC(SQL_NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
Case SQL-INVALID-HANDLE
MsgActual = "Handle Inválido"
CadErr = CadErr & Cr & MsgActual
lrc = rc
154
UltRegConsultaSQL = rc
Exit Function
Case SQL-NO-DATA-FOUND
MsgActual = "NO haymás datos"
CadErr = CadErr & Cr & MsgActual
lrc = rc
UltRegConsultaSQL = lrc
Exit Function
Case SQL-STILL-EXECUTING
lrc = rc
UltRegConsultaSQL = lrc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL_NULL-HENV, SQL-NULL-HDBCr CSQL.ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
UltRegConsultaSQL = lrc
Exit Function
End Select
'If CSQL.Registro.NumRegActMod MAX-DOEVS = O Then DoEvents
= CSQL.NumRegs
Loop Until CSQL.Registro.NumRegAct
'Asignar un dato a cada elemento de RSQL
For I = 1 To CSQL.NumCols
o)
sValor = String$ (BufferRet,
lvalor = O
rc = SQLGetData (CSQL. ID,
I, SQL-C-CHAR, sValor, BufferRet, 1Valor)
Select Case rc
Case SQL-SUCCESS
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.IDr MostrarErr)
CadErr = CadErr & MsgActual
lrc = rc
Case
SQL
-NO-DATA-FOUND
lrc = rc
UltRegConsultaSQL = lrc
Exit Function
Case
SQL
-STILL-EXECUTING
lrc = rc
UltRegConsultaSQL = lrc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBCr CSQL.ID, MostrarErr)
CadErr = CadErr & MsgActual
lrc = rc
UltRegConsultaSQL = lrc
Exit Function
End Select
'Verificar datos nulos
If lValor < 1 Then 'Dato con valor nulo
DatoCol = " "
'Dato
Else
con valor
algún
DatoCol = Left$ (sValor, 1Valor)
End I f
CSQL.Registro.DatosCol(1) = DatoCol
Next I
UltRegConsultaSQL = lrc
End Function
155
Public Function AntRegConsultaSQL(CSQL As ConsultaSQL, ByVal MostrarErr,
CadErrS) As Integer
Dim Cr As String
Cr = Chr(l3) & Chr(l0)
Dim RegAct As Long
Dim I As Integer
Dim sValor As String
* BufferRet
Dim lValor As Long
Dim DatoCol As String
Dim MsgActual As String
Dim lrc As Integer
lrc = SQL-SUCCESS
CadErr =
'Guarda el número de el registro actual
RegAct = CSQL.Registro.NumRegAct
'Si está en el primer registro simplemente sale sin hacer nada
I f RegAct <= 1 Then
AntRegConsultaSQL = lrc
Exit Function
End If
"I'
I************************************
'Regresa al inicj.0 de el registro
rc = RepUltimaConsulta (CSQL, MostrarErr, CadErr)
Select Case rc
Case SQL-SUCCESS
lrc = rc
Case SQL-SUCCESS-WITH-INFO
lrc = rc
Case SQL-ERROR
lrc = rc
AntRegConsultaSQL = lrc
Exit Function
Case SQL-INVALID-HANDLE
AntRegConsultaSQL = SQL-ERROR
Exit Function
End Select
'Hace el Fetch hasta encontrar
el registro anterioral actual
Do
'Obtiene un renglbn de
el resultado del Query
rc = SQLFetch (CSQL. ID)
'Prueba todos l o s posibles resultados derc
Select Case rc
Case SQL-SUCCESS
CSQL.Registro.NumRegAct = CSQL.Registro.NumRegAct + 1
lrc = rc
Case SQL SUCCESS WITH-INFO
CSQL.FegistroFNumRegAct = CSQL.Registro.NumRegAct + 1
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
Case SQL-NO-DATA -FOUND
lrc = rc
AntRegConsultaSQL = lrc
Exit Function
Case SQL INVALID-HANDLE
MsgAct%al = "Handle inválido"
CadErr = CadErr & Cr & MsgActual
lrc = rc
156
AntRegConsultaSQL = 1rc
Exit Function
Case SQL-STILL-EXECUTING
lrc = rc
AntRegConsultaSQL = lrc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQL.ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
AntRegConsultaSQL = lrc
Exit Function
End Select
Loop Until CSQL.Registro.NumRegAct
= RegAct - 1
If rc = SQL-SUCCESS Or rc = SQL-SUCCESS-WITH-INFO Then
‘Asignar un dato a cada elemento
de RSQL
For I = 1 To CSQL.NumCo1s
O)
sValor = String$ (BufferRet,
lValor = O
rc = SQLGetData(CSQL.ID, I, SQL-C-CHAR, SValor, BufferRet, 1Valor)
Select Case rc
Case SQL-SUCCESS
Case SQL-SUCCESS-WITH-INFO
MsgActual = DescErrorODBC(SQL-NULL-HENV, SQL-NULL-HDBC, CSQLvIDr MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
Case SQL-NO-DATA-FOUND
lrc = rc
AntRegConsultaSQL = lrc
Exit Function
Case SQL-STILL-EXECUTING
lrc = rc
AntRegConsultaSQL = 1rc
Exit Function
Case SQL-ERROR
MsgActual = DescErrorODBC(SQLNULL-HENV, SQL-NULL- HDBC,CSQL-ID, MostrarErr)
CadErr = CadErr & Cr & MsgActual
lrc = rc
AntRegConsultaSQL = lrc
Exit Function
End Select
‘Verificar datos nulos
If lValor < 1 Then ‘Dato con valor nulo
DatoCol =
Else
‘Dato
valor
algún
con
DatoCol = Left$ (sValor, 1Valor)
End If
CSQL.Registro.DatosCol(1) = DatoCol
Next I
End If
AntRegConsultaSQL = lrc
I”’
End
Function
Bibliografía
Whiting, Bill.
Teach yourself ODBC in 21 days.
SAMS, 1996.
Gryphon, Robert.
Using ODBC 2.
Que. 1995.
Geiger, Kyle.
Inside ODBC.
Microsoft. 1995.
Microsoft Publishing.
Programer's reference: Microsoft open database connectivity Software development kit, version
2.0
for the Microsoft Windows and Windows
NT operating systems.
Microsoft, 1994.
Reese, George.
Database programming with
JDBC and Java.
O'Reilly, 1997.
Hobbs, Ashton.
Teach yourself database programming wifh
JDBC in 27 days.
SAMS, 1997.
157
lndice
tratamiento deerrores, 8 1-82
BringWindowToTop, WinAPI, 12
A
Administrador de controladores deODBC. Véase
ODBC, Driver Manager
Administrador dehentes de datos deODBC, 3, 6
AntRegConsultaSQL,VB A P I , 71-72
A P I de JDBC
contra otras APIs, 88
descripción, 85
ejemplo de uso, 102-3
ejemplo de uso, completo,106-7
API de ODBC
aproximaciones deuso de la, 11
caracteristicas, 3
codificación directa, 1 1, 12
extensiones ala, 9
modelo de programación, 10, 12
niveles de conformidad, 51, 52
plataformas, 11
Apuntador de cadena, pasar
un, 38
Apuntadores en Visual Basic, 37
C
Cadena de conexión, 67
Cadena terminadaen nulo, 38
CadErrores, argumento de salida
VB A P I , 66, 74
CallableStatement,JDBC API, 92
Caracter de escape ( \ ), 103
CerrarInstrucSQL. VB API, 72-73
CLASSPATH, 104,105, 106
Códigos de retorno,ODBC API, 26,3 1
Códigos de retorno,VB A P I , 6 1
Compilar un programa de Java, 107
ConectarBD, VB M I , 65-66
ConectarBD2, VB API, 66-67
Conectividad a bases de datos abiertas. Véase ODBC,
definición de
Conexion.bas, módulo de Visual Basic, 65
Conexiones abiertas, 21
Conexiones ODBC múltiples
condiciones, 26
ejemplo, 25
Connection, JDBC API, 92, 100
ConsultaSQL, tipode dato abstracto, 61
Correr un programa compilado en Java, 108
B
Base of code, 14
BaseDatos, tipo de dato abstracto, 60
Bases de datos cruzadas, 5
Beep, WinAF'I, 12
Biblioteca de funciones de
Visual Basic
definiciones de constantes, 61
ejemplo de uso, 77-79
formato de aplicaciones,80
funciones denavegación, 71-72
funciones ODBC involucradas, 62-63
funciones privadas,74-75
limitaciones dela, 60
origen de la, 59
tipos de datos propios, 60-61
D
Data Source Name (DSN). Véase Nombre de fuente de
datos
DataBaseMetaData,JDBC M I , 92
DataTruncation, JDBC M I , 94
Date, JDBC A P I , 93
Declare, instrucción de VB, 12
DescErrorODBC, función privada VB API, 75
DesconectarBD, VB API,73-74
159
Driver Manager, ODBC API. Véase ODBC, Driver
Manager
Driver, JDBC A P I , 92,95
DriverManager, JDBC A P I , 93, 96
DriverPropertyInfo,JDBC A P I , 93
Drivers, deODBC, 5
Dynamic link library, 14
E
EjecutarSQL, VB API, 70-7 1
ERROR-FUNC, 61,66,67,69,70,71,72,75
ErroresNativos, VBM I , 63,74
EXITO-FUNC, 61,66,67,68, 69, 70, 71, 72, 75,81
EXITO-FUNC-CON-INFO, 61,66,67,68,69,70,71,
72,75
EXPORT TABLE. 14
F
Fuentes de datos
dar dealta, configurar, 6-7
registrar dentro del código, 7
Funciones dela WinAPI, 38, 39
Funciones deODBC
códigos de retorno,26, 3 1
de acuerdo a las instrucciones SQL,50
de conexión, 18
de liberación de recursos,21
del nivel 1, 54
del nivel 2, 55-56
del núcleo, 52-53
lineamientos de orden de llamada, 23-24
G
Generar la clase de Java, 107
GlobalAlloc, WinAPI, 38, 39,40,41
GlobalLock, WinAPI, 38,39,40,41
H
HacerConsultaSQL, VB API, 68-69
HacerEscDirectaSQL,VB MI,69-70
HacerEscrituraSQL, VBA P I , 70
Handle(s)
de ambiente, 15, 16
de conexión, 16
de sentencia, 18, 22,25,33, 34
HANDLE-INVALIDO, 61,69,70,72,75
HDBC, 3 1
HENV, 3 1
Herramientas deJDK, 103, 104, 105
HSTMT, 3 1
I
Información del error, ODBC API, 29
Instrucción SQL dinhica, I O0
Instrucci6n SQL estfitica, 1O0
Interfaz dealto nivel, 87
Interfaz de bajo nivel, 86
Interfaz de nivel de llamada, 9
Interfaz deProgramación de Aplicaciones,3
Interoperabilidad, 4
J
Java Development Kit (JDK), 91, 103
Java, intérprete del jdk,105-6
Javac, compiladordel jdk, 104-5
JavaSoft, 86,87, 109
JDBC
arquitectura de, 88
contra ODBC, 87-88
definición de, 85
descripción, 85
en Internet, 109
excepciones de, 94
funcionalidad, 86
interfaces de, 92-93
interfaces de alto nivel basadas en, 87
objetos de, 93-94
jdbcdrivers, propiedad, 96, 98
Jet database engine, 11
L
Liberar recursos de conexión, 21
Librería de enlacedinhico, 14, 15,60
Lstrcpy, WinAPI, 41
Lstrcpyn, WinAPI, 38,39,41
M
Manejo de cadenas de Visual Basic, 38
Manejo de errores
en la VB API, 81-82
Manejo simplede errores, 27
Mensajes de error
componentes de, 30
formatos de SQLError, 30
identidad del componente, 30
recuperar, 29
Método
acceptsURL, interfaz Driver, 95
close, interfaz Connection, 100
close, interfaz Statement, 100
connect, conexión con, 95-96
connect, interfaz Driver, 95
createstatement, interfaz Connection,100
executeQuery, interfaz Statement, 101
executeupdate, interfaz Statement, 1O 1
forName, objetoClass, 96
getconnection, conexión con,97-98
getConnection, objeto DriverManager, 97
getFloat, objeto Resultset, 101
getproperties, objetoSystem, 96
getResuItSet, interfaz Statement,101
161
getstring, objeto Resultset, 101
next, objeto Resultset, 101
setproperties, objeto System, 96
MCtodos
de la interfaz Driver, 95
del objeto DriverManager, 97
Middle-tier, modelo de acceso JDBC, 90
Modelo de codificación directa, arquitectura, 13
Modelo de programación, ODBC API, 10
MostrarErr, argumento de entrada VB API, 66, 75
Múltiples operaciones, 17-1 8
N
NECESITA-DATOS, 61
NO-HAY-MAS-DATOS, 01,72
Nombre de fuente de datos, 18
Números de error, 74, 79,81
O
Objetos de acceso a datos (DAO), 1 I
Objetos de datos remotos (RDO),1 1
ODBC
controladores de, 4
definición de, 3
Desktop Database Drivers, 5 , 6
Driver Manager, 5
en Internet, 56
funciones de nivel 1, 54
funciones de nivel 2, 55-56
núcleo de funciones, 5 1 , 52-53
porqué usar, 4
requisitos de conexión, 18
subprotocolo de. Véuse Subprotocolo ODBC en
URLs de JDBC
usar desde Java, 87-88
ODBC.IN1, 18
Odbc32.dl1, 5, 11, 14, 15, 37
Open Database Connectivity. Véuse ODBC, definición
de
Open Group Standard Structured Query Language, 4
P
Página Web de JavaSoft, 109
Páginas Web sobre ODBC, 56
Paquete java.sq1, 91
Plataformas, ODBC A P I , 11
Preparedstatement, JDBC API, 92
PriRegConsultaSQL, VB A P I , 71-72
Protocolos en URLs, 98
Puentes JDBC-ODBC, 87
Q
Quickview, I4
R
Recuperar columnas individuales, 46
Redireccionable, 14
RegisterDatabase, 7
RegistroSQL, tipo de dato abstracto, 60
RepUltimaConsulta, función privada VB API, 75
Requisitos conexión ODBC, 18
Resultset, JDBC API, 92, 101
ResultSetMetaData, JDBC API, 93, 102
RETCODE, 3 1
S
SDK ODBC, 5
SigRegConsultaSQL, VB API. 71-72
SIGUE-EJECUTANDO, 61
SQL Access Group, 3,29
SQL-NTS, 20,26,27,35,36
SQLAllocConnect, ODBC API, I7
SQLAllocEnv, ODBC API, 15-16
SQLAllocStmt, ODBC API, 33,34
SQLBindCol, ODBC API, 41-43
con cadenas de Visual Basic, 37,38-39
con tipos numkricos, 38
diferencia con SQLGetData, 46
función, 37
truncamiento de datos, 45
y la WinAPI, 39
SQLBrowseConnect, ODBC API, 19,55
SQLConnect, ODBC API, 19-20
SQLCHAR, 3 1
SQLDisconnect, ODBC API, 21-22
SQLDOUBLE, 3 1
SQLDriverConnect, ODBC API, 18, 19, 54, 63
SQLError, ODBC API, 27-29
SQLException, JDBC API, 94
SQLExecDirect, ODBC API, 35-36
SQLFetch, ODBC API, 44-45
SQLFreeConnect, ODBC API, 22-23
SQLFreeEnv, ODBC API, 23
SQLFreeStmt, ODBC API, 24
SQLGetData, ODBC M I , 4 7 4 9
recuperar columnas, 46
truncamiento de datos, 48
SQLGetFunctions, ODBC API, 19, 54
SQLGetInfo, ODBC API, 17, 18, 54
SQLHDBC, 3 I
SQLHENV, 3 1
SQLHSTMT, 3 1
SQLINTEGER, 3 1
SQLNumResultCols, ODBC A P I , 43,46, 53,63
SQLPOINTER, 3 1
SQLREAL, 3 1
SQLRETURN, 3 1
SQLSetConnectOption, ODBC A P I , 19, 54, 63
SQLSMALLINT, 3 1
SQLWarning, JDBC API, 94
Statement, JDBC API, 93, 100
Structured Query Language (SQL), 4,85
Subprotocolo ODBC en URLs de JDBC, 99
162
Sun Microsystems, 85, 91, 109
T
T-Prueba, tabla deejemplo, 77
Tabla de exportaci6n, 14
Three-tier, modelo de acceso JDBC, 90
Time, JDBC API, 93
Timestamp, JDBC A P I , 94
Tipos de datos, ODBC API, 3 1-32
Tipos de instrucciones SQL, 35
Two-tier, modelo de acceso JDBC, 89
Types, JDBC API, 94
UltRegConsultaSQL, VB API, 71-72
URL
de JDBC, descripcibn, 99
descripci6n de un, 98
protocolos en, 98
V
Variables de programa, asociar con columnas,37
Variables String de Visual Basic,37
X
X/Open and SQL AccessGroup Call Level Interface,
U
UAM Iztapalapa, 59
19,51
X/Open e ISO/IEC, 3
Descargar