Python y Btrieve 2 en Windows: Acceso a datos Zen con NoSQL
Corporación Actian
2 de febrero de 2018

En mi blog anterior ("Programming the Easy Way: Accediendo a una base de datos PSQL Zen con Python y ODBC"), mostré cómo acceder fácilmente a una base de datos Actian Zen con Python y ODBC. Mi siguiente proyecto era utilizar la nueva función Btrieve 2 con Python para interactuar directamente con los archivos de datos sin utilizar ningún SQL.
Los antiguos clientes de Btrieve/PSQL/Zen están familiarizados con la antigua función Btrieve, una interfaz de programación 3GL clásica que no ha cambiado realmente en más de 30 años. Proporciona acceso directo al motor para que pueda manipular archivos de datos con opciones como Crear, Abrir, Insertar, Actualizar, Eliminar, GetFirst, GetNext, GetEqual, etc. Ahora, con Actian Zen v13 disponemos de Btrieve 2, que ofrece una interfaz orientada a objetos simplificada y más intuitiva que cubre todo el conjunto de llamadas de Btrieve al motor de base de datos. Esta interfaz se proporciona para desarrolladores C/C++, pero también suministramos archivos SWIG (Simplified Wrapper & Interface Generator) para que la interfaz pueda ser utilizada por desarrolladores Python, Perl y PHP.
La configuración para utilizar Btrieve 2 con Python requiere unos pocos pasos:
- Prepare su entorno Windows:
- Instalar el motor de base de datos Actian Zen v13
- Instalar Python para Windows - He utilizado v3.6 64-bit de python.org
- Descargar y descomprimir Swig para Windows - He utilizado Swigwin-3.0.12 de swig.org
- Descargue y descomprima el SDK de Btrieve 2
- También se requiere Visual Studio 2015 o posterior; puedes instalar una versión Community de Microsoft si aún no la tienes desde aquí.
- Cree una carpeta MyPrograms para su código Python y copie los siguientes archivos del SDK de Btrieve 2:
- btrieveCpp.lib & btrieveC.lib de win64
- btrieveC.h & btrieveCpp.h de include
- btrievePython.swig & btrieveSwig.swig de swig
- Abra un símbolo del sistema, vaya a la carpeta MyPrograms e introduzca el siguiente comando:
<swigwin_location>swig -c++ -D_WIN64 -python btrievePython.swig
Esto crea los siguientes archivos: btrievePython.py & btrievePython_wrap.cxx - Crea un archivo de texto en MisProgramas llamado setup.py que contenga lo siguiente:
from distutils.core import setup, Extension btrievePython_module = Extension('_btrievePython', sources=['btrievePython_wrap.cxx'], library_dirs=['<MyPrograms location>'], libraries=['btrieveCpp'], ) setup (name='btrievePython', version='1.0', author='Actian', description="""Compile Btrieve 2 Python module""", ext_modules=[btrievePython_module], py_modules=["btrievePython"], )
- En un símbolo del sistema, en la carpeta MyPrograms, ejecute este comando para construir el módulo btrievePython:
python setup.py build_ext --plat-name="win-amd64"
Esto crea el archivo Python compilado buildlib.win-amd64-3.6_btrievePython.cp36-win_amd64.pyd - Cambie el nombre del archivo .pyd por _btrievePython.pyd y cópielo en MisProgramas o en la carpeta DLLs de su instalación de Python.
Una vez completados estos pasos, debería poder "importar btrievePython" en un entorno o programa Python.
Una vez configurada la biblioteca de importación btrievePython, ¡ya está listo para escribir aplicaciones Btrieve 2 en Python! He aquí un ejemplo que realiza las mismas operaciones de base de datos que la versión ODBC de mi blog anterior: crear el mismo archivo, insertar registros y recuperar el recuento total insertado. Este código es aproximadamente el doble de largo que la versión ODBC, pero accede al fichero directamente sin pasar por la capa SQL. (Nota - sólo se ha incluido una mínima comprobación de errores):
import os import sys import struct import btrievePython as btrv btrieveFileName = "Test_Table.mkd" recordFormat = "<iB32sBBBH" recordLength = 42 keyFormat = "<i" # Create a session: btrieveClient = btrv.BtrieveClient(0x4232, 0) # ServiceAgent=B2 # Specify FileAttributes for the new file: btrieveFileAttributes = btrv.BtrieveFileAttributes() rc = btrieveFileAttributes.SetFixedRecordLength(recordLength) # Specify Key 0 as an autoinc: btrieveKeySegment = btrv.BtrieveKeySegment() rc = btrieveKeySegment.SetField(0, 4, btrv.Btrieve.DATA_TYPE_AUTOINCREMENT) btrieveIndexAttributes = btrv.BtrieveIndexAttributes() rc = btrieveIndexAttributes.AddKeySegment(btrieveKeySegment) rc = btrieveIndexAttributes.SetDuplicateMode(False) rc = btrieveIndexAttributes.SetModifiable(True) # Create the file: rc = btrieveClient.FileCreate(btrieveFileAttributes, btrieveIndexAttributes, btrieveFileName, btrv.Btrieve.CREATE_MODE_OVERWRITE) if (rc == btrv.Btrieve.STATUS_CODE_NO_ERROR): print('nFile "' + btrieveFileName + '" created successfully!') else: print('nFile "' + btrieveFileName + '" not created; error: ', rc) # Allocate a file object: btrieveFile = btrv.BtrieveFile() # Open the file: rc = btrieveClient.FileOpen(btrieveFile, btrieveFileName, None, btrv.Btrieve.OPEN_MODE_NORMAL) if (rc == btrv.Btrieve.STATUS_CODE_NO_ERROR): print('File open successful!n') else: print('File open failed - status: ', rc, 'n') # Insert records: iinserting = True while iinserting: new_name = input('Insert name (Q to quit): ' ) if new_name.lower() == 'q': iinserting = False else: record = struct.pack(recordFormat, 0, 0, new_name.ljust(32).encode('UTF-8'), 0, 22, 1, 2018) rc = btrieveFile.RecordCreate(record) if (rc == btrv.Btrieve.STATUS_CODE_NO_ERROR): print(' Insert successful!') else: print(' Insert failed - status: ', rc) # Get Record count: btrieveFileInfo = btrv.BtrieveFileInformation() rc = btrv.BtrieveFile.GetInformation(btrieveFile, btrieveFileInfo) print('nTotal Records inserted =', btrieveFileInfo.GetRecordCount()) # Close the file: rc = btrieveClient.FileClose(btrieveFile) if (rc == btrv.Btrieve.STATUS_CODE_NO_ERROR): print('File closed successful!') else: print('File close failed - status: ', rc)
Dado que el ejemplo anterior no hace ninguna lectura de datos, volví atrás y añadí un poco más de código antes de cerrar el archivo para demostrar un escaneo de archivo que busca un nombre:
# Buscar registro por nombre ireading = True while ireading: encontrar_nombre = input('nEncontrar nombre (Q para salir): ' ) if nombre_encontrado.lower() == 'q': ireading = False else foundOne = False record = struct.pack(recordFormat, 0, 0, ' '.ljust(32).encode('UTF-8'), 0, 0, 0, 0) readLength = btrieveFile.RecordRetrieveFirst(btrv.Btrieve.INDEX_NONE, registro, 0) while (readLength > 0): recordUnpacked = struct.unpack(recordFormat, record) if (recordUnpacked[2] == find_name.ljust(32).encode('UTF-8')): print(' Registro coincidente encontrado: ID:', recordUnpacked[0], ' Nombre:', recordUnpacked[2].decode()) foundOne = True readLength = btrieveFile.RecordRetrieveNext(record, 0) if (foundOne == False): print(' No se ha encontrado ningún registro que coincida con "'+nombre_encontrado+'"') status = btrieveFile.GetLastStatusCode() if (status != btrv.Btrieve.STATUS_CODE_END_OF_FILE): print(' Error de lectura: ', status, btrv.Btrieve.StatusCodeToString(status))
La sencillez de la programación en Python, combinada con la nueva interfaz de desarrollo Btrieve 2, permitirá la rápida creación de nuevas aplicaciones Zen.
Si tiene alguna pregunta sobre Zen u otros productos Actian, no dude en preguntar en los foros de nuestra comunidad.
Suscríbase al blog de Actian
Suscríbase al blog de Actian para recibir información sobre datos directamente en su correo electrónico.
- Manténgase informado: reciba lo último en análisis de datos directamente en su bandeja de entrada.
- No se pierda ni una publicación: recibirá actualizaciones automáticas por correo electrónico que le avisarán cuando se publiquen nuevas publicaciones.
- Todo depende de usted: cambie sus preferencias de entrega para adaptarlas a sus necesidades.