Base de Datos Oracle: desarrollo de aplicaciones
Interfaz OCI
jul-04 Alberto M.F.A. [email protected] 2
Contenidos� Tecnologías nativas ORACLE� Plataforma Windows� Plataforma JAVA
jul-04 Alberto M.F.A. [email protected] 3
Tecnologías ORACLE� OCI � Oracle Call Interfaz
� 3GL� C/C++, COBOL, FORTRAN
� Precompiladores� Pro C/C++� Pro COBOL� Pro FORTRAN� SQLJ para java
jul-04 Alberto M.F.A. [email protected] 4
OCI� Interfaz de más bajo nivel disponible en
el cliente� Encima de Net8� OCI es un API procedural para
lenguajes de 3ª generación� C / C++� Cobol � Fortran
jul-04 Alberto M.F.A. [email protected] 5
OCI y Net8
jul-04 Alberto M.F.A. [email protected] 6
Características del API� Permite obtener mucho rendimiento� Pro-C, ODBC, OleDB, ADO, JDBC sobre OCI� Incluye funciones para:
� Control de sesiones� Transacciones� SQL dinámico� Acceso a Objetos Oracle� Arrays en sentencias SQL� Manejo de Threads (Thread Safe)
jul-04 Alberto M.F.A. [email protected] 7
Características avanzadas� Interfaces para estructuras internas� Gestión de varias sesiones concurrentes� Client-side Object cache� Maneja objetos con SQL o punteros C� Conversión entre tipos C y Oracle� OTT� Oracle Advanced Queing (OA)
jul-04 Alberto M.F.A. [email protected] 8
Inconvenientes� Muchas funciones en el API� Con muchos parámetros� Excesivo uso de void*� Para portabilidad tipos de datos C
Oracle � (cast)� API muy complejo
jul-04 Alberto M.F.A. [email protected] 9
Compilación
jul-04 Alberto M.F.A. [email protected] 10
Compilación� Ficheros de cabecera
� #include <oci.h>� $ORA_HOME/oci/include
� Librerías compiladas para ANSI C:� Borland C++ 5.0 � $ORA_HOME/oci/lib/bc� MVC++ 6.0 � $ORA_HOME/oci/lib/msvc
jul-04 Alberto M.F.A. [email protected] 11
Programación: pasos básicos� Crear variable de entorno� Crear handlers y estructuras� Conectar al servidor e iniciar
sesión� Ejecutar transacciones SQL y
procesar� Cerrar sesión y desconectar� Liberar handlers y estructuras
jul-04 Alberto M.F.A. [email protected] 12
Proceso y entorno� Todas las transacciones se ejecutan en
un entorno (OCIEnv)� Un Proceso OCI soporta múltiples
entornos
jul-04 Alberto M.F.A. [email protected] 13
Proceso y entorno
jul-04 Alberto M.F.A. [email protected] 14
Estructuras de datos OCI� Son áreas de datos opacas, ocultas al
programa, dentro de la librería.� Se referencian a través de *handlers.� Se crean con llamadas al API� Dos tipos:
� Handlers� Descriptores
jul-04 Alberto M.F.A. [email protected] 15
Handlers� Punteros a estructuras ocultas� Guardan información sobre:
� Contexto y conexión� Errores y funciones OCI
Solo Algunos...
jul-04 Alberto M.F.A. [email protected] 16
Handlers� Se pasan en todas las llamadas� La mayoría dependen del Handle de
entorno� Hay relación jerárquica entre ellos
� Creación de OCIEnv OCICreateEnv(...)
jul-04 Alberto M.F.A. [email protected] 17
Jerarquía de Handlers� Casi todos dependen de OCIEnv
jul-04 Alberto M.F.A. [email protected] 18
Creación de Handlers� De entorno OCIEnv:OCIEnvCreate(&Env,OCI_DEFAULT,...
� Resto de Handlers:OCIHandleAlloc(Env, &Error,OCI_HTYPE_ERROR, 0, NULL);
jul-04 Alberto M.F.A. [email protected] 19
Destrucción de handlers� Para todos
OCIHandleFree(...)
� Si se elimina el de entorno, todos liberados (jerarquía)
OCIHandleFree(Env, OCI_HTYPE_ENV)
jul-04 Alberto M.F.A. [email protected] 20
Handlers principales� Environment � OCIEnv� Error � OCIError� Service Context � OCISvcCtx
� Server � OCIServer� UserSesion � OCISesion
� Statement � OCIStmt� Bind � OCIBind� Define � OCIDefine
jul-04 Alberto M.F.A. [email protected] 21
Atributos de handlers� Cada atributo representa información
guardada en el handle� Cada handler tiene atrib. Especificos� Hay que Asociar explicitamente los
atributos al handlerOCIAttrSet(...)
OCIAttrGet(...)
jul-04 Alberto M.F.A. [email protected] 22
Uso de memoria OCI� OCICreateEnv, OCIHandleAlloc y
OCIDescriptorAlloc() permiten reservar memoria de la librería
� Útil para datos de cliente con mismo ciclo de vida que el handle
� Parámetro xtramem_sz� La librería la libera al eliminar el handle� Evita “leaks” de memoria
jul-04 Alberto M.F.A. [email protected] 23
Descriptores� Mantienen información sobre conceptos
“dentro” de la BD (¿metainformación?)� Funciones:OCIDescriptorAlloc(...)
OCIDescriptorFree(...)
jul-04 Alberto M.F.A. [email protected] 24
Tipos de descriptores� OCISnapshot � Instántanea� OCILOBLocator � CLOB, BLOB� OCIParam � describe calls� OCIRowid � bind-define rowids� OCINotify � publish-suscribe� OCIAQ... �mensajes
jul-04 Alberto M.F.A. [email protected] 25
Inicialización de la aplicación� Varios modos
� Shared Mode, cuando:� Varias instancias de la misma aplicación en la misma
máquina para distintos clientes� Se ejecuta la misma sentencia en la misma o distintas
conexiones� Es un driver SQL u otro middleware
� Threaded� Events� Default
jul-04 Alberto M.F.A. [email protected] 26
Inicialización� Los modos anteriores pueden
combinarse con el operador |:mode = (OCI_THREADED | OCI_OBJECT)
� Con las funciones:OCIEnvCreate(...)
OCIInitialize(...) ���� depre
jul-04 Alberto M.F.A. [email protected] 27
Conexión y sesión� Dos modos:
� Aplicaciones para único usuario y conexión por BDOCILogon(...)
� Múltiples sesiones o conexionesOCIServerAttach(...)
OCISessionBegin(...)
jul-04 Alberto M.F.A. [email protected] 28
Conexión sencillaOCIEnvCreate(&Env, ...)
OCIHandleAlloc(Env, &Error, ...)
OCILogon(Env, Error
, &Servicio ����
, “user”
, “pass”
, “database”)
jul-04 Alberto M.F.A. [email protected] 29
Conexión compleja� Crear entorno� Crear conexión� Crear sesión� Poner sesión en contexto de servicio
� Muchas posibilidades:� Conexión a varias máquinas� Varias sesiones por máquina� Migración de sesiones entre conexiones
jul-04 Alberto M.F.A. [email protected] 30
Entorno y conexiónOCIEnvCreate(&Env, ...)
OCIHandleAlloc(Env, &Error, ...)
OCIHandleAlloc(Env, &Server, ...)
OCIServerAttach(Server, “maquina”,...)
jul-04 Alberto M.F.A. [email protected] 31
Sesión y servicioOCIHandleAlloc(Env, &Sesion, ...)
OCIAttrSet(Sesion, “user”, ...)
OCIAttrSet(Sesion, “pass”, ...)
OCIHandleAlloc(Env, &Servicio, ...)
OCISessionBegin(Servicio, Sesion, ...)
OCIAttrSet(Servicio, Server, ...)
OCIAttrSet(Servicio, Sesion, ...)
jul-04 Alberto M.F.A. [email protected] 32
Ejecución de sentencias� Ubicar Handlers� Preparación� Bind de variables� Define de variables� Ejecutar� Fetch para recuperar datos (SELECT )� Liberar handlers
jul-04 Alberto M.F.A. [email protected] 33
Ejecución de sentencias
Caso complejo con SQL dinámico
jul-04 Alberto M.F.A. [email protected] 34
Creación de handlerOCIHandleAlloc(Env
, &hStmt ����
, OCI_HTYPE_STMT
, ...);
jul-04 Alberto M.F.A. [email protected] 35
Preparación� Se precompila
� Validación sintáctica y semántica� Preparación de estructuras en memoria� Se cachea la precompilación � importante si
muchas ejecuciones repetidas
OCIStmtPrepare(hStmt, Error, “Sentencia SQL”
, OCI_NTV_SYNTAX ���� Sintaxis, ...);
jul-04 Alberto M.F.A. [email protected] 36
Bind y Define� Bind: asociar variables de entrada a la
sentencia con variables del programa� Define: asociar variables de salida de la
sentencia a las del programaSELECT ename, sal, comm INTO:emp_name, :salary, :commission
FROM emp
WHERE ename = :emp_number;
jul-04 Alberto M.F.A. [email protected] 37
Placeholders� Marcadores dentro de la sentencia� Sintaxis :<nombre>� Solo validos para datos, no para
estructura
INSERT INTO :emp ���� InválidoVALUES (12345, ’OERTEL’,’WRITER’, 50000, 30)
jul-04 Alberto M.F.A. [email protected] 38
Placeholders� También en PL/SQL
char plsql_statement[] =
"BEGIN \
RAISE_SALARY(:emp_number,:new_sal); \
END;";
jul-04 Alberto M.F.A. [email protected] 39
Formas de Bind y Define� ByName
OCIBindByName(...)
OCIDefineByName(...)
� ByPosOCIBindByPos(...)
OCIDefineByPos(...)
jul-04 Alberto M.F.A. [email protected] 40
OCI<Bind/Define>ByName()status = OCIBindByName(hStmt
, &bnd1 � Handler, hError
, (text *)":ENAME” � Placeholder, strlen(":ENAME”) � sizeof(“:ename”), emplName � Puntero a var, EMPL_NAME_LENGTH + 1 � sizeof(variable), SQLT_STR � Tipo dato, NULL, NULL, NULL, 0, NULL
, OCI_DEFAULT );
jul-04 Alberto M.F.A. [email protected] 41
OCI<Bind/Define>ByPos()status = OCIDefineByPos(hStmt
, &dfn1 � Handler, Error
, 1 � Posición, deptName � Puntero a Var., sizeof(deptName)+1 � Tamaño, SQLT_STR � Tipo dato, NULL, NULL, NULL
, OCI_DEFAULT);
jul-04 Alberto M.F.A. [email protected] 42
sizeof(<B/D variable>)� Atención al tipo de dato (strings)
jul-04 Alberto M.F.A. [email protected] 43
Indicación de situaciones especiales� En BIND o DEFINE:
� Truncamientos por longitud� NULL’s
� En OCI<B/D>By<Name/Pos>() se puede dar un puntero a sb2� Tipo definido en algún .h de OCI
jul-04 Alberto M.F.A. [email protected] 44
Indicadores en Bind
jul-04 Alberto M.F.A. [email protected] 45
Indicadores en Define
jul-04 Alberto M.F.A. [email protected] 46
Ejemplo indicadoresOCIBindByName(hStmt
, bnd2
, Error
, (text *)":JOB"
, -1
, ud->emplJob
, EMPL_JOB_LENGTH + 1
, SQLT_STR
, &indB2 ���� Puntero a sb2, NULL, NULL, 0, NULL, OCI_DEFAULT);
jul-04 Alberto M.F.A. [email protected] 47
Empleo de indicadores� Al dar un dato a sentencia:
� Si NULL � ind = -1;
� Resto de casos � dato=3; ind=0;
� Al leer un resultado a sentencia:� Si NULL � ind == -1;
� Resto de casos �
if (ind >= 0) expr = dato * ...;
jul-04 Alberto M.F.A. [email protected] 48
Ejecución de sentenciasstatus = OCIStmtExecute(
SvcCtx � handler servicio, hStmt � handler sentencia, Error � handler de error, 1 � nº de iteraciones, 0 � index en array si iter, NULL � snap-in, NULL � snap-out, OCI_DEFAULT);� modo
jul-04 Alberto M.F.A. [email protected] 49
Lectura de resultados� Si la sentencia retorna un conjunto de
datos (cursor)� Hay que iterar por el resultado
� Si la sentencia devuelve una sola fila� OCIStatementExecute() ya deja los
resultados en las variables asociadas con OCIDefineBy<name/pos>() y actualiza los indicadores.
jul-04 Alberto M.F.A. [email protected] 50
Iteración por el resultadoOCIStatementExecute(...)
while (hay datos)
{
proceso de datos ...
OCIStmtFetch(...)
}
jul-04 Alberto M.F.A. [email protected] 51
Iteración por el resultadostatus = OCIStmtFetch(
hStmt
, Error
, 1 � Nº filas a recuperar
, OCI_FETCH_NEXT � Movimiento de cursor
, OCI_DEFAULT
);
jul-04 Alberto M.F.A. [email protected] 52
Ajustes de iteraciones� Para minimizar RoundTrips al servidor
se pueden ajustar cosas como:� Prefetch, cantidad de filas traídas en cada
lectura� Cantidad de memoria para prefetch
� Con OCIAttrSet(...)
jul-04 Alberto M.F.A. [email protected] 53
Transacciones� OCI soporta varios niveles de
transacción:� Simple local� Serializable o Read-only� Global
jul-04 Alberto M.F.A. [email protected] 54
Transacciones simples� Cada sentencia inicia una Trx� A OCIStatementExecute() se le
puede indicar que trabaje en modoOCI_COMMIT_ON_SUCCESS
� Si no (OCI_DEFAULT) hay que cerrar las transacciones explícitamente� Si éxito COMMIT� Si fallo ROLLBACK
jul-04 Alberto M.F.A. [email protected] 55
Trx Serializables o Read-only� Se inician explicitamente con
OCITransStart(...)
� Se debe parar el modo:� OCI_TRANS_SERIALIZABLE� OCI_TRANS_READONLY
jul-04 Alberto M.F.A. [email protected] 56
Trx globales� Son transacciones sofisticadas� Intervienen varios agentes� Pueden ser ramificadas� Commit en una o dos fases
� One-Phase commit� Two-Phase commit
jul-04 Alberto M.F.A. [email protected] 57
Commit y RollBack� OCITransCommit(...)
status = OCITransCommit(
SvcCtx, Error, OCI_DEFAULT);
� OCITransRollBack(...)status = OCITransCommit(
SvcCtx, Error, OCI_DEFAULT);
jul-04 Alberto M.F.A. [email protected] 58
Terminación de la aplicación� OCISessionEnd(...)
� OCIServerDetach(...)
� Para cada handle� OCIHandleFree(...)
� Alternativa:� OCIHandleFree(OCIEnv,...
jul-04 Alberto M.F.A. [email protected] 59
Manejo de errores� Cada llamada al API devuelve un status
status = OCI<funcion>(...
� Se debería verificar el status después de cada llamada� Puede dejar el código muy farragoso� Al menos chequear después de cada paso
importante� Acumular varios resultados (|| o |=)
jul-04 Alberto M.F.A. [email protected] 60
Si status != OCI_SUCCESS� Se puede llamar a OCIGetError() para
recuperar información adicional.
� Se puede llamar repetidamente a OCIGetError() para recuperar todos los mensajes.� Cuando no hay más:
(status = OCIGetError()) == OCI_NO_DATA