Extracción SQLite de herramientas, métodos y trampas de tablas de Oracle

por calpee

Introducción

SQLite Database es un bulto de programa muy exitoso y ubicuo que es en parte importante irreconocible para la red social de TI por norma general. Dr. Richard Hipp diseñó y codificó SQLite Third Major Revision sirve a varios clientes en segmentos de mercado con requisitos críticos de calidad de programa que SQLite ha cumplido al realizar el estándar de aviónica DO-178B. Aparte de tener una fuerte presencia en las industrias aeroespacial y automotriz, la mayor parte de los primordiales distribuidores de S.O. (incluidos Oracle, Microsoft, Apple, Google plus y RedHat) tienen dentro SQLite como el ingrediente primordial del S.O..

Existen algunas características con las que tienen la posibilidad de tropezar los individuos de otros ámbitos RDBMS. SQLite se conoce como una banco de información de “tipos flexibles”, en contraste a Oracle, que aplica rigurosamente los modelos de datos de columna; Los valores de letras y números se tienen la posibilidad de insertar apropiadamente en columnas SQLite declaradas como enteros (si bien las limitaciones de verificación tienen la posibilidad de acrecentar la rigidez del tipo SQLite, si se quiere). Más allá de que varios procesos simultáneos tienen la posibilidad de leer desde una banco de información SQLite, solo un desarrollo tiene ingreso de escritura al unísono (las apps que necesitan escritores simultáneos tienen que llevar cuidado con SQLite). No hay una plataforma de trabajo de red y todas y cada una de las conexiones se efectúan mediante un sistema de ficheros; SQLite no incorpora un modelo cliente-servidor. No hay una restauración puntual y las operaciones de respaldo son fundamentalmente al estilo de Oracle 7. ALTER DATAFILE BEGIN BACKUP creando de esta forma una copia congruente de las transferencias en la banco de información. GRANT y REVOKE no están incorporados en SQLite, que utiliza privilegios del sistema de ficheros para todos y cada uno de los controles de ingreso. No hay un desarrollo en background y los clientes del servicio que comienzan sesión últimamente tienen la posibilidad de retrasarse y ser causantes de la búsqueda de transferencias, la recopilación de estadísticas u otras funcionalidades administrativas que se ejecutan en background en esta “banco de información no administrada”. Una parte de la historia y la arquitectura de SQLite se puede observar en las grabaciones de audio y vídeo del Dr. Se tienen la posibilidad de leer discusiones sobre hipps.

Pese a estas características, SQLite es probablemente un formato superior para el trueque de datos en comparación con CSV, XML o aun JSON, puesto que se tienen la posibilidad de integrar índices que dejan a los receptores efectuar consultas de gran velocidad en SQL92 sin preprocesamiento, licencia o activación. El estilo de codificación conservador y los comentarios de SQLite están premeditados a favorecer a los “futuros desarrolladores que aún no han nacido”, y la Biblioteca del Congreso de los USA definió el formato de banco de información en disco como el estándar de almacenaje en un largo plazo.

Se muestran tres métodos para copiar tablas de bases de datos Oracle a SQLite: trueque CSV, links de bases de datos ODBC y scripts PHP. El trueque de CSV puede efectuarse con una herramienta que existe y un shell POSIX sin que se haga una intervención administrativa por medio de una cuenta a la que se logre entrar con los datos de destino. El procedimiento unixODBC necesita que un gestor compile, instale y configure las fuentes de datos ODBC de SQLite y después use Oracle. se adhiere a ellos dg4odbc, el diseño ODBC del servidor Oracle. El enfoque de scripting PHP deja que los modelos de LOB se muevan, pero posiblemente se requiera un compilador y un ambiente de avance para prepararlos.

Obtener el contenido de la banco de información Oracle en SQLite es un inconveniente pues las clases de datos básicos no están absolutamente ajustados. Aquí presentaré herramientas para forzar la alineación y obtener con la transformación adecuada.

Se piensa que el usuario tiene ingreso a una banco de información Oracle y la sqlplus Herramienta de línea de comandos y conocimiento de de qué manera emplearla (asimismo se puede emplear SQLcl).

Seguridad SQLite

SQLite se enfoca en que los programadores compilen el código fuente de la banco de información en sus apps, y las herramientas a nivel de sistema semejan padecer alguna desidia. La herramienta de línea de comandos de administración de bases de datos, sqlite3, se proporciona para Linux en la compilación de herramientas. Las últimas ediciones tienen ciertas peculiaridades novedosas atrayentes, pero hay suficientes inconvenientes binarios compilados que desaconsejaría.

  • La herramienta unicamente se compila para ámbitos Linux x86 de 32 bits y se apoya en bibliotecas compartidas, lo que tiene 2 inconvenientes:
    • Muchas distribuciones de Linux AMD64 / x86_64 modernas no poseen libc u otras bibliotecas dependientes de manera ya establecida que necesitan ingreso administrativo para su instalación.
    • Linux de 32 bits deja que un programa use un máximo de 3 gigas de memoria, lo que puede limitar de forma inadecuada la clasificación y el almacenaje en caché en el momento en que hay considerablemente más RAM física libre y se puede emplear en modo de 64 bits.
  • la sqlite3 La seguridad del compilador distribuida en la compilación de herramientas no posee la seguridad del compilador activada, como lo señala el icono hardening-check Herramienta que se puede conseguir en EPEL.

Estos son los desenlaces de la prueba de dureza para la herramienta Linux Tools distribuida por SQLite:

$ hardening-check sqlite3; archivo sqlite3
sqlite3:
 Position Independent Executable: no, habitual executable!
 Stack protected: no, not found!
 Fortify Source functions: no, only unprotected functions found!
 Read-only relocations: no, not found!
 Immediate binding: no, not found!
sqlite3: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (emplees shared libs), for GNU/Linux 4.3.0, stripped

Sugiero que la descarga de la fuente (en la actualidad sqlite-autoconf-3360000.tar.gz) se consiga y prepare en S.O. modernos con comprobaciones de seguridad del compilador actualizadas:

CFLAGS='-O3 -D_FORTIFY_SOURCE=2 -fstack-asegurador-strong -fpic -pie' \
LDFLAGS='-Wl,-z,relro,-z,now -Wl,-z,now' ./configure

Suponiendo que se haya hecho esto, todas y cada una de las comprobaciones de seguridad del compilador están habilitadas:

$ hardening-check sqlite3; archivo sqlite3
sqlite3:
 Position Independent Executable: yes
 Stack protected: yes
 Fortify Source functions: yes (some protected functions found)
 Read-only relocations: yes
 Immediate binding: yes
sqlite3: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (emplees shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=34ffa395a5f985b16f6ac2y también6c7c3ad5126y también05bed, not stripped

SQLite es una infraestructura y, si bien aguardamos que sea invulnerable, debe respetar la seguridad de los compiladores modernos. Cualquier compilador que logre explotar estas opciones debería llevarlo a cabo.

LDD

Con SQLite puede determinar las próximas afinidades de datos básicos para las columnas de una tabla. Las filas que conforman las columnas tienen la posibilidad de ser: NULL o uno de estos tipos salvo NUMERIC:

  • TEXTO: cadena de artículo guardada con codificación de banco de información (UTF-8, UTF-16BE o UTF-16LE).
  • BLOB: blob de datos, guardado precisamente como se ingresó.
  • NUMÉRICO: número genérico, procura pasar a un número entero o real.
  • INTEGER – firmado, guardado en 1, 2, 3, 4, 6 u 8 bytes, en dependencia del tamaño del valor.
  • REAL: valor de coma flotante, guardado en formato IEEE-754 de 8 bytes.

Estos tipos no encajan de manera perfecta con Oracle.

El oráculo NUMBER type se emplea para contener tanto números enteros como reales, en dependencia de de qué forma se use la “escala de datos”. de Oracle CHAR y VARCHAR2 Tarjeta para el TEXT Art. Eso DATE tipo no funciona de manera directa en SQLite, y lo vamos a tratar como un INTEGER de momento.

La afinidad numérica de SQLITE no existe al investigar el código fuente. Unicamente se verifican los primeros letras y números de un género de datos de columna; si no se reconoce, se le da el tipo numérico. Evaluar:

$ sqlite3
SQLite version 3.36.0 2021-06-18 18:36:39
Entrar ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.

sqlite> CREATE TABLE foo(bar razzamataz,ch text,fl real,whl int,mess blob);

sqlite> .dump foo
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE foo(bar razzamataz,ch text,fl real,whl int,mess blob);
COMMIT;

sqlite> create table bar as select * from foo where 1=0;

sqlite> .dump bar
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE bar(
  bar NUM,
  ch TEXT,
  fl REAL,
  whl INT,
  mess
);
COMMIT;

la CREATE TABLE AS SELECT La operación previo (CTAS) llama a la función C createTableStmtque han extraído afinidades de columna preferidas. El tipo irreconocible “razzamataz” se asignó numéricamente tácitamente y el género de mácula se suprimió completamente. La keyword NUM en la tabla de barras tampoco se reconoce. Este es el procedimiento mucho más simple que encontré en SQLite para saber las afinidades de datos reales de una columna.

Las afinidades reales de la columna SQLite establecidas en el código fuente son:

** Substring     | Affinity
** --------------------------------
** 'INT'         | SQLITE_AFF_INTEGER
** 'CHAR'        | SQLITE_AFF_TEXT
** 'CLOB'        | SQLITE_AFF_TEXT
** 'TEXT'        | SQLITE_AFF_TEXT
** 'BLOB'        | SQLITE_AFF_BLOB
** 'REAL'        | SQLITE_AFF_REAL
** 'FLOA'        | SQLITE_AFF_REAL
** 'DOUB'        | SQLITE_AFF_REAL
** If none of the substrings in the above table are found,
** SQLITE_AFF_NUMERIC is returned.

Las clases binarios de Oracle (LONG, BLOB, RAW, etcétera.) unicamente se tienen la posibilidad de desplazar usando una herramienta mucho más vigorosa como PHP, que se detalla mucho más adelante en este archivo. Algún otro género de oráculo exótico es dependiente del lector.

Ahora se expone un script de extracción de tabla de lenguaje de definición de datos (DDL) para Oracle sqlplus que se puede emplear para hacer tablas compatibles en SQLite:

$ cat textract_ddl.sql
equipo pages 50000 lin 32767 verify off heading off retroalimentación off newpage none
variable own varchar2(128);
variable nam varchar2(128);
execute :own := upper('&1');
execute :nam := upper('&2');
select null, 'create table ' || :nam || ' (' from dual;
select sep, substr(col,1,cl) col, dtype, num,
case when lag(num) over (order by num) = num - 1 then null else '*' end chk from
(
  select case when COLUMN_ID = 1 then null else ',' end sep, COLUMN_NAME col,
                                        'TEXT --' dtype,        COLUMN_ID num,
  (select max(length(COLUMN_NAME)) from ALL_TAB_COLUMNS
    where OWNER = :own and TABLE_NAME = :nam) cl
  from   ALL_TAB_COLUMNS
  where  OWNER      = :own
  and    TABLE_NAME = :nam
  and    DATA_TYPE IN ('CHAR', 'VARCHAR', 'VARCHAR2') --'CLOB', 'NCLOB' ...
  union all
  select case when COLUMN_ID = 1 then null else ',' end sep, COLUMN_NAME col,
         case when data_scale  = 0 then 'INT --'
              when data_scale <> 0 then 'REAL --'
                                   else 'NUM --' end dtype, COLUMN_ID num,
  (select max(length(COLUMN_NAME)) from ALL_TAB_COLUMNS
    where OWNER = :own and TABLE_NAME = :nam) cl
  from   ALL_TAB_COLUMNS
  where  OWNER      = :own
  and    TABLE_NAME = :nam
  and    DATA_TYPE  = 'NUMBER'
  union all
  select case when COLUMN_ID = 1 then null else ',' end sep, COLUMN_NAME col,
                                        'INT --date' dtype,     COLUMN_ID num,
  (select max(length(COLUMN_NAME)) from ALL_TAB_COLUMNS
    where OWNER = :own and TABLE_NAME = :nam) cl
  from   ALL_TAB_COLUMNS
  where  OWNER      = :own
  and    TABLE_NAME = :nam
  and    DATA_TYPE  = 'DATE'
  order by num
)
union all select null, ');', null, null, null from dual;

Para probar una condición de fallo utilizando este script, tenemos la posibilidad de utilizarlo contra el ALL_VIEWS Vista que comunmente tienen la posibilidad de ver todos y cada uno de los individuos que comienzan sesión. Esta vista tiene dentro un LONG -Columna que necesita un cliente mucho más fuerte como PHP.

Intente realizar el script de una manera u otra sqlplus o SQLcl crea una columna marcada (y también ignorada):

SQL> start textract_ddl sys all_views

  create table all_views (
  OWNER 			 TEXT --	     1 *
, VIEW_NAME			 TEXT --	     2
, TEXT_LENGTH			 NUM --		     3
, TYPE_TEXT_LENGTH		 NUM --		     5 *
, TYPE_TEXT			 TEXT --	     6
, OID_TEXT_LENGTH		 NUM --		     7
, OID_TEXT			 TEXT --	     8
, VIEW_TYPE_OWNER		 TEXT --	     9
, VIEW_TYPE			 TEXT --	    10
, SUPERVIEW_NAME		 TEXT --	    11
, EDITIONING_VIEW		 TEXT --	    12
, READ_ONLY			 TEXT --	    13
  );

Los números de columna 1 y 5 precedentes indican un fallo en la función de la ventana LAG en esta línea. La columna 1 todavía se comunica en todos y cada ejecución, pero algún otro indicio señala un género de datos no aceptado (en un caso así, un LONG en la columna 4).

Un desafío mucho más sutil es la carencia de un data_scale en valores enteros. Una carrera contra ellos ALL_OBJECTS La visión siguiente exhibe el inconveniente:

SQL> start textract_ddl sys all_objects

  create table all_objects (
  OWNER 			 TEXT --	     1 *
, OBJECT_NAME			 TEXT --	     2
, SUBOBJECT_NAME		 TEXT --	     3
, OBJECT_ID			 NUM --		     4
, DATA_OBJECT_ID		 NUM --		     5
, OBJECT_TYPE			 TEXT --	     6
, CREATED			 INT --date	     7
, LAST_DDL_TIME 		 INT --date	     8
, TIMESTAMP			 TEXT --	     9
, STATUS			 TEXT --	    10
, TEMPORARY			 TEXT --	    11
, GENERATED			 TEXT --	    12
, SECONDARY			 TEXT --	    13
  );

Los 2 de arriba NUM columnas de todos modos poseen números enteros, no números de coma flotante. Este inconveniente tiende a suceder en el momento en que una columna hace aparición como. se define NUMBER en Oracle sin precisión ni escalado. Puede ser útil ver ciertos ejemplos de los diversos tipos numéricos de Oracle:

SQL> create table testab(n1 number(5,3), n2 number (5,0), n3 number(*,0), n4 number(5), n5 number);

Table created.

SQL> select column_name, data_type, data_precision, data_scale from user_tab_columns where table_name="TESTAB";

COLUMN_NAME DATA_TYPE DATA_PRECISION DATA_SCALE
----------- --------- -------------- ----------
N1          NUMBER    5              3
N2          NUMBER    5              0
N3          NUMBER                   0
N4          NUMBER    5              0
N5          NUMBER

SQL> insert into testab values(3.141592653589, 2.718281828, 1.414, 22/7, (1+sqrt(5))/2);

1 row created.

SQL> select * from testab;

        N1         N2         N3         N4         N5
---------- ---------- ---------- ---------- ----------
     3.142          3          1          3 1.61803399

SQL> start textract_ddl fishecj testab

  create table testab (
  N1				  REAL --	      1 *
, N2				  INT --	      2
, N3				  INT --	      3
, N4				  INT --	      4
, N5				  NUM --	      5
  );

Si está convencido de que una columna de números de Oracle tiene dentro números enteros aun si no se detalla la escala, cambie el género de columna de forma manual.

Tenemos la posibilidad de utilizar el shell de línea de comando SQLite para hacer una banco de información y el ALL_OBJECTS Tabla como és, incluyendo la NUM Columnas (tenga presente que la herramienta de shell no devuelve mensajes de confirmación):

$ sqlite3 orasys.db3
SQLite version 3.36.0 2021-06-18 18:36:39
Entrar ".help" for usage hints.
sqlite>   create table all_objects (
   ...>   OWNER          TEXT --     1 *
   ...> , OBJECT_NAME    TEXT --     2
   ...> , SUBOBJECT_NAME TEXT --     3
   ...> , OBJECT_ID      NUM --      4
   ...> , DATA_OBJECT_ID NUM --      5
   ...> , OBJECT_TYPE    TEXT --     6
   ...> , CREATED        INT --date  7
   ...> , LAST_DDL_TIME  INT --date  8
   ...> , TIMESTAMP      TEXT --     9
   ...> , STATUS         TEXT --    10
   ...> , TEMPORARY      TEXT --    11
   ...> , GENERATED      TEXT --    12
   ...> , SECONDARY      TEXT --    13
   ...>   );

Con bases de datos muy enormes, tiene sentido aumentar al máximo el tamaño de la página SQLite. Esto disminuye levemente la sobrecarga de memoria y disminuye el tamaño del fichero para tablas idénticas:

sqlite> pragma page_size=65536;
sqlite> vacuum;

SQLite asimismo ha establecido Write Ahead Logging, que tiene una secuencia de virtudes pero asimismo muestra restricciones. Si se quiere el modo perfecto WAL, actívelo con el PRAGMA journal_mode=WAL; Asignación.

En este punto aceptamos que nuestras tablas SQLite en este momento están establecidas en nuestro fichero de banco de información y listas para recibir los datos extraídos de Oracle.

sqlite> .quit

LMD

El primordial inconveniente de esta sección es la impresión de fecha y hora.

Como se mentó en la discusión previo sobre afinidades de datos, no hay formatos originarios de fecha u hora en SQLite. Hay funcionalidades de conversión de fecha que se manifiestan en los próximos géneros de datos SQLite:

  • TEXTO como cadenas ISO8601 (“AAAA-MM-DD HH: MM: SS.SSS”).
  • VERDADERO como el número de días julianos, el número de días desde el mediodía en Greenwich el 24 de noviembre de 4714 AC. AD según el calendario proléptico gregoriano.
  • INTEGER como UNIX Epoch Time, el número de segundos desde 1970-01-01 00:00:00 UTC.

Tiempo REAL el formato previo es probablemente el mucho más próximo a la representación interna de Oracle, el formato de la era UNIX es mucho más pequeño y tiene habilidades de conversión en Oracle que están mejor descritas. Tenemos la posibilidad de saber los límites de tiempo de la temporada UNIX de 32 bits con un pequeño script de Gawk:

$ cat strftime.gawk
#!/bin/gawk -f
BEGIN 

Una versión anterior de gawk en una plataforma de 32 bits permitía marcas de tiempo de época negativas que se remontaban a diciembre de 1901 (tenga en cuenta que estas horas se expresan en relación con la zona horaria local, en este caso CST):

$ ./strftime.gawk -2147483648 0 2147483647
1901/12/13 14:45:52
1969/12/31 18:00:00
2038/01/18 21:14:07

Las versiones más nuevas de gawk no permiten marcas de tiempo de época negativas (curiosamente, el awk busybox moderno no comparte esta limitación):

$ ./strftime.gawk -2147483648
gawk: ./strftime.gawk:2: fatal: strftime: second argument less than 0 or too big for time_t

Los tiempos máximos que pueden expresarse usando gawk y transferirse fácilmente a Oracle en un sistema de 64 bits parecen ser:

$ ./strftime.gawk 0 253402322399 67767976233554395
1969/12/31 18:00:00
9999/12/31 23:59:59
2147483647/12/31 23:59:52

Esta situación está documentada principalmente en la wiki para el año 2038.

Oracle tiene un sitio web con capacidades de conversión para traducir Oracle DATE Ingrese la hora de UNIX. Tenga en cuenta que he ajustado los tiempos mínimo / máximo, el límite inferior a los resultados anteriores y el límite superior al último segundo del año 9999, ya que es seguro hacerlo en la era UNIX de 64 bits. A continuación, presento una versión modificada de esta función de conversión que devuelve los valores mínimo / máximo cuando se desborda y no es un error:

CREAR O REEMPLAZAR LA FUNCIÓN date_to_unixts (oracle_date IN DATE) RETURN PLS_INTEGER IS unix_epoch DATE: = TO_DATE (‘1970101000000’, ‘AAAAMMDDHH24MISS’); date_max DATUM: = AU_DATE (‘20380101000000’, ‘AAAAMMDDHH24MISS’); min_date FECHA: = TO_DATE (‘19030101000000’, ‘AAAAMMDDHH24MISS’); unix_ts PLS_INTEGER; INICIO SI oracle_date> max_date ENTONCES return (2147483647); ELSIF date_oracle

CREATE OR REPLACE
FUNCTION date_to_unixts(oracle_date IN DATE) RETURN NUMBER IS
  unix_epoch DATE := TO_DATE('19700101000000','YYYYMMDDHH24MISS');
  max_date   DATE := TO_DATE('99991231235959','YYYYMMDDHH24MISS');
  min_date   DATE := TO_DATE('19011213194552','YYYYMMDDHH24MISS');
  unix_ts    NUMBER(38,0);
BEGIN
  IF    oracle_date > max_date THEN return(253402322399);
  ELSIF oracle_date < min_date THEN return(-2147483648);
  ELSE  unix_ts := (oracle_date - unix_epoch) / (1/86400);
  END IF;
  RETURN (unix_ts);
END;
/

Una vez que esa función esté en su lugar, podemos obtener una SELECT Esto extrae todas las columnas de destino de una tabla de Oracle, pero convierte específicamente los tipos de fecha al formato de época de UNIX. Para hacer esto, un SELECT lo que el convertidor llama explícitamente DATE Se requieren columnas:

$ cat textract_dml.sql
set pages 50000 lin 32767 verify off heading off feedback off newpage none
variable own varchar2(128);
variable nam varchar2(128);
execute :own := upper('&1');
execute :nam := upper('&2');
select null, 'select' from dual;
select sep, substr(col,1,cl) col, com, num from
(
  select decode(COLUMN_ID, 1, '', ',') sep,
         COLUMN_NAME col,
        '--' com, COLUMN_ID num,
  (select max(length(COLUMN_NAME))+16 from ALL_TAB_COLUMNS
    where OWNER = :own and TABLE_NAME = :nam) cl
  from   ALL_TAB_COLUMNS
  where  OWNER      = :own 
  and    TABLE_NAME = :nam
  and    DATA_TYPE IN ('CHAR', 'VARCHAR2', 'NUMBER')
  union all
  select decode(COLUMN_ID, 1, '', ',') sep,
         'date_to_unixts(' || COLUMN_NAME || ')' col,
         '--' com, COLUMN_ID num,
  (select max(length(COLUMN_NAME))+16 from ALL_TAB_COLUMNS
    where OWNER = :own and TABLE_NAME = :nam) cl
  from   ALL_TAB_COLUMNS
  where  OWNER      = :own
  and    TABLE_NAME = :nam
  and    DATA_TYPE  = 'DATE'
  order by num
);
select null, 'from '||:own||'.'||:nam||';', null from dual;

La consulta a exportar ALL_OBJECTS es inferior.

SQL> spool all_objects-dump.sql

SQL> start textract_dml sys all_objects

  select
  OWNER                         --  1
, OBJECT_NAME                   --  2
, SUBOBJECT_NAME                --  3
, OBJECT_ID                     --  4
, DATA_OBJECT_ID                --  5
, OBJECT_TYPE                   --  6
, date_to_unixts(CREATED)       --  7
, date_to_unixts(LAST_DDL_TIME) --  8
, TIMESTAMP                     --  9
, STATUS                        -- 10
, TEMPORARY                     -- 11
, GENERATED                     -- 12
, SECONDARY                     -- 13
  from sys.all_objects;
SQL> spool off

Echa una ojeada de cerca a eso all_objects-dump.sql y ajuste la solicitud para la exportación SQLite precisamente, nada más y nada menos.

Probablemente halla causas para cambiar el SQL generado por el script:

  • Al exportar múltiples tablas a SQLite, puede ser favorable exportarlas todas y cada una como se dieron a conocer últimamente a fin de que todas y cada una de las tablas sean "congruentes en lectura". Esto se hace con el AS OF una cláusula SELECT Declaración, y el usuario debe tener el "Flashback habilitado"
    “Un privilegio en todos y cada mesa para poder ver una versión histórica. El espacio de tabla de Oracle UNDO asimismo debe tener bastante tiempo de retención para reconstruir las imágenes de restauración.
  • Cualquier recargo WHERE El contenido de la cláusula que limita la visibilidad de las filas debe agregarse en este punto (en vez de remover filas de SQLite tras la transferencia).
  • Solo las ediciones de SQLite siguientes a la 3.25 tienen funcionalidades de ventana. Si se necesita la salida de una función de ventana y esa función no está libre en la implementación de SQLite de destino, agréguela a Oracle antes de transferirla.
  • Todas y cada una de las transformaciones de datos (por servirnos de un ejemplo, funcionalidades de subcadena para adecentar campos char / varchar de datos poco relevantes o insignificantes, cambios digitales concretos del propósito, etcétera.) se efectúan mejor como una parte de la transferencia, en vez de adecentar tras la transferencia.
  • Orquestación - CSV

    Con una banco de información SQLite coincidente definida y una solicitud que filtra adecuadamente los datos extraídos, la transferencia de datos en este momento es viable.

    El enfoque en esta sección incluye el modo perfecto de exportación / importación CSV que se usa en Oracle sqlplus y el shell de línea de comandos SQLite. Esta transferencia tiene rincón en una "tubería con nombre" (FIFO); el fichero CSV jamás va a existir en el disco duro. Esta técnica se emplea de manera frecuente con las herramientas de exportación / importación de Oracle.

    Ahora se expone un script de shell POSIX para efectuar esta transferencia, probado con el panel de Debian:

    $ cat textract.sh
    #!/bin/sh
    
    equipo -eu             # http://redsymbol.net/articles/unofficial-bash-strict-mode/
    #equipo -euo pipefail  # http://redsymbol.net/articles/unofficial-bash-strict-mode/
    IFS=$'\n\t' head='SET HEADING OFF FEEDBACK OFF MARKUP CSV ON' #TNS='/ as sysdba'
    
    #TNS="(description=          \
    #       (address=            \
    #         (protocol=tcp)     \
    #         (host=db.myco.com) \
    #         (port=1521))       \
    #       (connect_data=       \
    #         (sid=orcl)))"
    
    [ -z "$" ] && 
    
    while getopts f:n:p:s:t:u: arg
    do case "$arg" in
            f) fILE="$OPTARG" ;;
            n)  TNS="$OPTARG" ;;
    #       p) pASS="$OPTARG" ;;
            s) sqlX="$OPTARG" ;;
            t) tABL="$OPTARG" ;;
            u) uSER="$OPTARG" ;;
       esac
    done
    
    getv () 
    
    getv sqlX "Oracle Extraction SQL filename: " && exit
    getv TNS  -n "Source Oracle database: "      && exit
    getv fILE -n "Destination sqlite archivo: "     && exit
    getv tABL -n "Destination sqlite table: "    && exit
    getv uSER -n "Usuario (default $LOGNAME): "     && uSER="$LOGNAME"
    
    echo "Logging in / executing as $uSER."
    
    DIR="$(mktemp -d "/tmp/$(basename "$0" ".sh")XXXXX")"
    FIFO="$DIR/fifo.lst" GET="$DIR/get.sql" PUT="$DIR/put.sql"
    mkfifo "$FIFO"
    
    trap 'stty echo; rm -fv "$FIFO" "$GET" "$PUT"; rmdir -v "$DIR"' EXIT
    
    [ -z "$" ] &&
      
    
    echo "$head
    spool $FIFO" > "$GET"
    cat "$sqlX" >> "$GET"
     
    ( sqlplus -silent "$uSER/$pASS@$TNS" "@$" |
      sed -n '0~10000p' ) &
    
    unset pASS
     
    echo ".mode csv
    .import $ $" > "$PUT"
    
    sqlite3 "$fILE" ".read $PUT"
    
    wait

    El guion debe tener múltiples Los elementos deben efectuar un movimiento de tabla y los pide si no están detallados. Preste particular atención al TNS (sustrato de red transparente); Hay ejemplos comentados de de qué manera el script está negado en un fin particularmente, así sea ejecutándose como un sysDBA local o con un descriptor terminado para una banco de información recóndita, si no están establecidos y -n si falta la opción, se le va a preguntar.

    Ciertas variantes de este script se tienen la posibilidad de realizar en Windows. POSIX Win32 Busybox Shell no incorpora mkfifo; Cygwin o WSL podrían ser una opción mejor.

    Los requisitos y el accionar del script se tienen la posibilidad de detallar mejor con un caso de muestra de un tiempo de ejecución de exportación:

    $ time ./textract.sh -f orasys.db3 -u fishecj \
    	-s all_objects-dump.sql -t all_objects
    Logging in / executing as fishecj.
    Password:
    "SCOTT","EMPPK",,10775,20472,"INDEX",1366667998,1369409340,"2013-04-22:21:59:58","VALID","N","N","N"
    "TIGER","DEPT",,29780,,"SYNONYM",1371564246,1371564246,"2013-06-18:14:04:06","VALID","N","N","N"
    removed ‘/tmp/textractpH3qJ/fifo.lst’
    removed ‘/tmp/textractpH3qJ/get.sql’
    removed ‘/tmp/textractpH3qJ/put.sql’
    rmdir: removing directory, ‘/tmp/textractpH3qJ’
    
    real   0m7.885s
    usuario   0m0.448s
    sys    0m0.078s
    • Hay uno comentado -p Opción para concretar la contraseña de la cuenta de Oracle en la línea de comando; esto no debe emplearse puesto que está ingresado en el historial de comandos y puede mostrarse como un razonamiento en / proc / * / cmdline.
    • Cuando se ejecuta el script, los dos sqlplus y sqlite se comunicará a través del fifo.lst desarrollado en el directorio temporal y debe usarse como únidad central de procesamiento consumidora en el top Informe.
    • Una de cada 10,000 líneas de CSV procesadas se imprime en la salida estándar para señalar actividad continua; si no lo quiere, retire el sed y redirigirlos sqlplus Salida al dispositivo nulo. Completamente silencio, quita eso -v Opciones en la salida trap.
    • la date_to_unixts La ocupación ha de estar aparente en el momento en que se ejecuta el script, así sea como un elemento desarrollado en la cuenta local o a través de un homónimo concedido por otro dueño.
    • Si está usando bash o korn, utilice el modo perfecto riguroso "símbolo colorado". El shell POSIX de Dash de Debian no se incorpora, no equipo -o; En el momento en que su shell lo lleve a cabo, habilítelo.
    • Al depurar el script, es útil tener el trap desatar.
    • Hay una biblioteca SQLite que da el semejante de tablas ajenas para un enfoque alterno al procesamiento CSV.

    La transferencia de ALL_OBJECTS ha de ser parcialmente veloz (7 segundos como se expone arriba). Confirme el número de líneas y DATEs de Oracle sqlplus y SQLite:

    SQL> select count
    

    Una versión anterior de gawk en una plataforma de 32 bits permitía marcas de tiempo de época negativas que se remontaban a diciembre de 1901 (tenga en cuenta que estas horas se expresan en relación con la zona horaria local, en este caso CST):

    $ ./strftime.gawk -2147483648 0 2147483647
    1901/12/13 14:45:52
    1969/12/31 18:00:00
    2038/01/18 21:14:07

    Las versiones más nuevas de gawk no permiten marcas de tiempo de época negativas (curiosamente, el awk busybox moderno no comparte esta limitación):

    $ ./strftime.gawk -2147483648
    gawk: ./strftime.gawk:2: fatal: strftime: second argument less than 0 or too big for time_t

    Los tiempos máximos que pueden expresarse usando gawk y transferirse fácilmente a Oracle en un sistema de 64 bits parecen ser:

    $ ./strftime.gawk 0 253402322399 67767976233554395
    1969/12/31 18:00:00
    9999/12/31 23:59:59
    2147483647/12/31 23:59:52

    Esta situación está documentada principalmente en la wiki para el año 2038.

    Oracle tiene un sitio web con capacidades de conversión para traducir Oracle DATE Ingrese la hora de UNIX. Tenga en cuenta que he ajustado los tiempos mínimo / máximo, el límite inferior a los resultados anteriores y el límite superior al último segundo del año 9999, ya que es seguro hacerlo en la era UNIX de 64 bits. A continuación, presento una versión modificada de esta función de conversión que devuelve los valores mínimo / máximo cuando se desborda y no es un error:

    CREAR O REEMPLAZAR LA FUNCIÓN date_to_unixts (oracle_date IN DATE) RETURN PLS_INTEGER IS unix_epoch DATE: = TO_DATE ('1970101000000', 'AAAAMMDDHH24MISS'); date_max DATUM: = AU_DATE ('20380101000000', 'AAAAMMDDHH24MISS'); min_date FECHA: = TO_DATE ('19030101000000', 'AAAAMMDDHH24MISS'); unix_ts PLS_INTEGER; INICIO SI oracle_date> from all_objects;

    COUNTUna versión anterior de gawk en una plataforma de 32 bits permitía marcas de tiempo de época negativas que se remontaban a diciembre de 1901 (tenga en cuenta que estas horas se expresan en relación con la zona horaria local, en este caso CST):

    $ ./strftime.gawk -2147483648 0 2147483647
    1901/12/13 14:45:52
    1969/12/31 18:00:00
    2038/01/18 21:14:07

    Las versiones más nuevas de gawk no permiten marcas de tiempo de época negativas (curiosamente, el awk busybox moderno no comparte esta limitación):

    $ ./strftime.gawk -2147483648
    gawk: ./strftime.gawk:2: fatal: strftime: second argument less than 0 or too big for time_t

    Los tiempos máximos que pueden expresarse usando gawk y transferirse fácilmente a Oracle en un sistema de 64 bits parecen ser:

    $ ./strftime.gawk 0 253402322399 67767976233554395
    1969/12/31 18:00:00
    9999/12/31 23:59:59
    2147483647/12/31 23:59:52

    Esta situación está documentada principalmente en la wiki para el año 2038.

    Oracle tiene un sitio web con capacidades de conversión para traducir Oracle DATE Ingrese la hora de UNIX. Tenga en cuenta que he ajustado los tiempos mínimo / máximo, el límite inferior a los resultados anteriores y el límite superior al último segundo del año 9999, ya que es seguro hacerlo en la era UNIX de 64 bits. A continuación, presento una versión modificada de esta función de conversión que devuelve los valores mínimo / máximo cuando se desborda y no es un error:

    CREAR O REEMPLAZAR LA FUNCIÓN date_to_unixts (oracle_date IN DATE) RETURN PLS_INTEGER IS unix_epoch DATE: = TO_DATE ('1970101000000', 'AAAAMMDDHH24MISS'); date_max DATUM: = AU_DATE ('20380101000000', 'AAAAMMDDHH24MISS'); min_date FECHA: = TO_DATE ('19030101000000', 'AAAAMMDDHH24MISS'); unix_ts PLS_INTEGER; INICIO SI oracle_date>
    ----------
    23699

    SQL> select created, last_ddl_time from all_objects where object_name="EMPPK";

    CREATED LAST_DDL_TIME
    ------------------- -------------------
    2013-04-22 21:59:58 2013-05-24 15:29:00

    Estos desenlaces de Oracle no coinciden precisamente con SQLite en el momento en que verificamos DATEs precaución:

    $ sqlite3 orasys.db3
    SQLite version 3.36.0 2021-06-18 18:36:39
    Entrar ".help" for usage hints.
    
    sqlite> select count
    

    Una versión anterior de gawk en una plataforma de 32 bits permitía marcas de tiempo de época negativas que se remontaban a diciembre de 1901 (tenga en cuenta que estas horas se expresan en relación con la zona horaria local, en este caso CST):

    $ ./strftime.gawk -2147483648 0 2147483647
    1901/12/13 14:45:52
    1969/12/31 18:00:00
    2038/01/18 21:14:07

    Las versiones más nuevas de gawk no permiten marcas de tiempo de época negativas (curiosamente, el awk busybox moderno no comparte esta limitación):

    $ ./strftime.gawk -2147483648
    gawk: ./strftime.gawk:2: fatal: strftime: second argument less than 0 or too big for time_t

    Los tiempos máximos que pueden expresarse usando gawk y transferirse fácilmente a Oracle en un sistema de 64 bits parecen ser:

    $ ./strftime.gawk 0 253402322399 67767976233554395
    1969/12/31 18:00:00
    9999/12/31 23:59:59
    2147483647/12/31 23:59:52

    Esta situación está documentada principalmente en la wiki para el año 2038.

    Oracle tiene un sitio web con capacidades de conversión para traducir Oracle DATE Ingrese la hora de UNIX. Tenga en cuenta que he ajustado los tiempos mínimo / máximo, el límite inferior a los resultados anteriores y el límite superior al último segundo del año 9999, ya que es seguro hacerlo en la era UNIX de 64 bits. A continuación, presento una versión modificada de esta función de conversión que devuelve los valores mínimo / máximo cuando se desborda y no es un error:

    CREAR O REEMPLAZAR LA FUNCIÓN date_to_unixts (oracle_date IN DATE) RETURN PLS_INTEGER IS unix_epoch DATE: = TO_DATE ('1970101000000', 'AAAAMMDDHH24MISS'); date_max DATUM: = AU_DATE ('20380101000000', 'AAAAMMDDHH24MISS'); min_date FECHA: = TO_DATE ('19030101000000', 'AAAAMMDDHH24MISS'); unix_ts PLS_INTEGER; INICIO SI oracle_date> from all_objects;
    23699

    sqlite> select * from all_objects where object_name="EMPPK";
    SCOTT|EMPPK||10775.0|20472.0|INDEX|1366667998|1369409340|2013-04-22:21:59:58|VALID|N|N|N

    sqlite> select datetime(CREATED, 'unixepoch', 'localtime'), datetime(LAST_DDL_TIME, 'unixepoch', 'localtime') from all_objects where object_name="EMPPK";
    2013-04-22 16:59:58|2013-05-24 10:29:00

    sqlite> select datetime(CREATED, 'unixepoch'), datetime(LAST_DDL_TIME, 'unixepoch') from all_objects where object_name="EMPPK";
    2013-04-22 21:59:58|2013-05-24 15:29:00

    sqlite> .quit

    la DATEs difieren en su región horaria local salvo que se suprima el razonamiento localtime.

    Tenemos la posibilidad de hacer y llenar una pequeña tabla de Oracle para corroborar que tenemos la posibilidad de sobrepasar el límite de 2038:

    create table birthday (who varchar2(4000), theday date);
    insert into birthday values ('joe',  to_date('2030/04/01','YYYY/MM/DD'));
    insert into birthday values ('jane', to_date('2040/05/01','YYYY/MM/DD'));
    insert into birthday values ('jed',  to_date('2050/06/01','YYYY/MM/DD'));
    insert into birthday values ('jill', to_date('9999/12/31','YYYY/MM/DD'));
    commit;

    Tras el desarrollo de exportación previo:

    sqlite> select * from birthday;
    joe|1901232000
    jane|2219443200
    jed|2537654400
    jill|253400000000
    
    sqlite> select who, datetime(theday, 'unixepoch', 'localtime') from birthday;
    joe|2030-03-31 19:00:00
    jane|2040-04-30 18:00:00
    jed|2050-05-31 18:00:00
    jill|9999-12-05 02:53:20
    
    sqlite> select who, datetime(theday, 'unixepoch') from birthday;
    joe|2030-04-01 00:00:00
    jane|2040-05-01 00:00:00
    jed|2050-06-01 00:00:00
    jill|9999-12-05 08:53:20

    La temporada no nos transporta en el final de 9999, pero está bastante cerca.

    dg4odbc

    El modo perfecto de transferencia CSV previo es considerablemente más fiable que dg4odbccomo detallan los desenlaces de esta sección. Los links de bases de datos de manera directa en SQLite son atractivos por el hecho de que tienen la posibilidad de proteger la integridad de las transferencias, pero el diseño es frágil y vulnerable a fallos.

    Sin un contrato de soporte activo de Oracle, dg4odbc no debe nombrarse para empleo de producción con SQLite. Esos que utilizan la banco de información XE gratis de Oracle sin soporte tienen que eludir esto dg4odbc En el momento en que todo es viable. El bulto del servidor ODBC tiene dentro la observación: "El controlador se puede usar, pero puede contener fallos". Úselo bajo su peligro.

    Para disponer ODBC, se tienen que disponer los próximos packs del S.O.:

    # yum install sqlite sqlite-devel unixODBC unixODBC-devel
    Loaded plugins: langpacks, ulninfo
    Package sqlite-3.7.17-8.el7_7.1.x86_64 already installed and latest version
    Package unixODBC-2.3.1-14.0.1.el7.x86_64 already installed and latest version
    Resolving Dependencies
    --> Running transaction check
    ---> Package sqlite-devel.x86_64 0:3.7.17-8.el7_7.1 will be installed
    ---> Package unixODBC-devel.x86_64 0:2.3.1-14.0.1.el7 will be installed
    --> Finished Dependency Resolution
    
    Dependencies Resolved
    
    ================================================================================
     Package             Arch        Version                  Repository       Size
    ================================================================================
    Installing:
     sqlite-devel        x86_64      3.7.17-8.el7_7.1         ol7_latest      104 k
     unixODBC-devel      x86_64      2.3.1-14.0.1.el7         ol7_latest       54 k
    
    Transaction Summary
    ================================================================================
    Install  2 Packages
    
    Total download size: 158 k
    Installed size: 552 k
    Is this ok [y/d/N]: y
    Downloading packages:
    (1/2): unixODBC-devel-2.3.1-14.0.1.el7.x86_64.rpm          |  54 kB   00:00     
    (2/2): sqlite-devel-3.7.17-8.el7_7.1.x86_64.rpm            | 104 kB   00:03     
    --------------------------------------------------------------------------------
    Total                                               47 kB/s | 158 kB  00:03     
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
      Installing : sqlite-devel-3.7.17-8.el7_7.1.x86_64                         1/2 
      Installing : unixODBC-devel-2.3.1-14.0.1.el7.x86_64                       2/2 
      Verifying  : unixODBC-devel-2.3.1-14.0.1.el7.x86_64                       1/2 
      Verifying  : sqlite-devel-3.7.17-8.el7_7.1.x86_64                         2/2 
    
    Installed:
      sqlite-devel.x86_64 0:3.7.17-8.el7_7.1                                        
      unixODBC-devel.x86_64 0:2.3.1-14.0.1.el7                                      
    
    Complete!

    El bulto ODBC de SQLite se distribuye en formato fuente. Para los sistemas basados ​​en RedHat, hay un RPM de origen que puede hacer packs de manera fácil instalables. Consíguelo y compile el bulto binario con el próximo comando (que necesita un compilador C instalado):

    rpmbuild --rebuild sqliteodbc-0.9998-1.src.rpm

    En el momento en que la colección esté completa, puede hallar los packs compilados en la próxima localización:

    $ ll ~/rpmbuild/RPMS/x86_64/
    total 408
    -rw-rw-r--. 1 cfisher cfisher 120440 Jul 12 19:08 sqliteodbc-0.9998-1.x86_64.rpm
    -rw-rw-r--. 1 cfisher cfisher 294704 Jul 12 19:08 sqliteodbc-debuginfo-0.9998-1.x86_64.rpm

    Instale los packs deseados en los servidores de destino:

    # rpm -Uvh ~fishecj/rpmbuild/RPMS/x86_64/sqliteodbc-0.9998-1.x86_64.rpm
    Preparing...                          ################################# [100%]
    Updating / installing...
       1:sqliteodbc-0.9998-1              ################################# [100%]
    odbcinst: Controlador installed. Usage count increased to 1. 
        Objetivo directory is /etcétera

    Eche una ojeada al fichero README:

    # rpm -ql sqliteodbc
    /usr/lib64/libsqlite3_mod_blobtoxy-0.9998.so
    /usr/lib64/libsqlite3_mod_blobtoxy.so
    /usr/lib64/libsqlite3_mod_csvtable-0.9998.so
    /usr/lib64/libsqlite3_mod_csvtable.so
    /usr/lib64/libsqlite3_mod_impexp-0.9998.so
    /usr/lib64/libsqlite3_mod_impexp.so
    /usr/lib64/libsqlite3_mod_xpath-0.9998.so
    /usr/lib64/libsqlite3_mod_xpath.so
    /usr/lib64/libsqlite3_mod_zipfile-0.9998.so
    /usr/lib64/libsqlite3_mod_zipfile.so
    /usr/lib64/libsqlite3odbc-0.9998.so
    /usr/lib64/libsqlite3odbc.so
    /usr/share/doc/sqliteodbc-0.9998
    /usr/share/doc/sqliteodbc-0.9998/ChangeLog
    /usr/share/doc/sqliteodbc-0.9998/README
    /usr/share/doc/sqliteodbc-0.9998/license.terms

    Vea que se ha añadido la especificación del controlador:

    # cat /etcétera/odbcinst.ini
    [ODBC Driver 11 for SQL Server]
    Description=Microsoft ODBC Controlador 11 for SQL Server
    Controlador=/opt/microsoft/msodbcsql/lib64/libmsodbcsql-11.0.so.2270.0
    Threading=1
    UsageCount=1
    
    [SQLITE3]
    Description=SQLite ODBC 3.X
    Controlador=/usr/lib64/libsqlite3odbc.so
    Setup=/usr/lib64/libsqlite3odbc.so
    Threading=2
    FileUsage=1
    UsageCount=1

    Asimismo se ha añadido un identificador global falso:

    # tail -2 /etcétera/odbc.ini
    [SQLite3 Datasource]
    Controlador=SQLITE3

    Como root, añada un controlador para un fichero de banco de información SQLite concreto desarrollado en la última sección (tenga presente que el /etcétera/odbc.ini es global para todos y cada uno de los individuos y está sujeto a los privilegios del sistema de ficheros; Se tienen la posibilidad de hacer ficheros odbc.ini privados, pero no se tratan aquí):

    echo '
    
    [SQLitec1]
    Description=textract PoC
    Controlador=/usr/lib64/libsqlite3odbc.so
    Database=/home/oracle/orasys.db3
    # optional lock timeout in milliseconds
    Timeout=2000' >> /etcétera/odbc.ini

    Pruebe el controlador con la herramienta ODBC SQL:

    # isql SQLitec1
    +---------------------------------------+
    | Connected!                            |
    |                                       |
    | sql-statement                         |
    | help [tablename]                      |
    | quit                                  |
    |                                       |
    +---------------------------------------+
    
    SQL> select count
    

    Una versión anterior de gawk en una plataforma de 32 bits permitía marcas de tiempo de época negativas que se remontaban a diciembre de 1901 (tenga en cuenta que estas horas se expresan en relación con la zona horaria local, en este caso CST):

    $ ./strftime.gawk -2147483648 0 2147483647
    1901/12/13 14:45:52
    1969/12/31 18:00:00
    2038/01/18 21:14:07

    Las versiones más nuevas de gawk no permiten marcas de tiempo de época negativas (curiosamente, el awk busybox moderno no comparte esta limitación):

    $ ./strftime.gawk -2147483648
    gawk: ./strftime.gawk:2: fatal: strftime: second argument less than 0 or too big for time_t

    Los tiempos máximos que pueden expresarse usando gawk y transferirse fácilmente a Oracle en un sistema de 64 bits parecen ser:

    $ ./strftime.gawk 0 253402322399 67767976233554395
    1969/12/31 18:00:00
    9999/12/31 23:59:59
    2147483647/12/31 23:59:52

    Esta situación está documentada principalmente en la wiki para el año 2038.

    Oracle tiene un sitio web con capacidades de conversión para traducir Oracle DATE Ingrese la hora de UNIX. Tenga en cuenta que he ajustado los tiempos mínimo / máximo, el límite inferior a los resultados anteriores y el límite superior al último segundo del año 9999, ya que es seguro hacerlo en la era UNIX de 64 bits. A continuación, presento una versión modificada de esta función de conversión que devuelve los valores mínimo / máximo cuando se desborda y no es un error:

    CREAR O REEMPLAZAR LA FUNCIÓN date_to_unixts (oracle_date IN DATE) RETURN PLS_INTEGER IS unix_epoch DATE: = TO_DATE ('1970101000000', 'AAAAMMDDHH24MISS'); date_max DATUM: = AU_DATE ('20380101000000', 'AAAAMMDDHH24MISS'); min_date FECHA: = TO_DATE ('19030101000000', 'AAAAMMDDHH24MISS'); unix_ts PLS_INTEGER; INICIO SI oracle_date> from all_objects;
    +-----------+
    | countUna versión anterior de gawk en una plataforma de 32 bits permitía marcas de tiempo de época negativas que se remontaban a diciembre de 1901 (tenga en cuenta que estas horas se expresan en relación con la zona horaria local, en este caso CST):

    $ ./strftime.gawk -2147483648 0 2147483647
    1901/12/13 14:45:52
    1969/12/31 18:00:00
    2038/01/18 21:14:07

    Las versiones más nuevas de gawk no permiten marcas de tiempo de época negativas (curiosamente, el awk busybox moderno no comparte esta limitación):

    $ ./strftime.gawk -2147483648
    gawk: ./strftime.gawk:2: fatal: strftime: second argument less than 0 or too big for time_t

    Los tiempos máximos que pueden expresarse usando gawk y transferirse fácilmente a Oracle en un sistema de 64 bits parecen ser:

    $ ./strftime.gawk 0 253402322399 67767976233554395
    1969/12/31 18:00:00
    9999/12/31 23:59:59
    2147483647/12/31 23:59:52

    Esta situación está documentada principalmente en la wiki para el año 2038.

    Oracle tiene un sitio web con capacidades de conversión para traducir Oracle DATE Ingrese la hora de UNIX. Tenga en cuenta que he ajustado los tiempos mínimo / máximo, el límite inferior a los resultados anteriores y el límite superior al último segundo del año 9999, ya que es seguro hacerlo en la era UNIX de 64 bits. A continuación, presento una versión modificada de esta función de conversión que devuelve los valores mínimo / máximo cuando se desborda y no es un error:

    CREAR O REEMPLAZAR LA FUNCIÓN date_to_unixts (oracle_date IN DATE) RETURN PLS_INTEGER IS unix_epoch DATE: = TO_DATE ('1970101000000', 'AAAAMMDDHH24MISS'); date_max DATUM: = AU_DATE ('20380101000000', 'AAAAMMDDHH24MISS'); min_date FECHA: = TO_DATE ('19030101000000', 'AAAAMMDDHH24MISS'); unix_ts PLS_INTEGER; INICIO SI oracle_date> |
    +-----------+
    | 23699 |
    +-----------+
    SQLRowCount returns 0
    1 rows fetched

    SQL> select datetime(CREATED, 'unixepoch'), datetime(LAST_DDL_TIME, 'unixepoch') from all_objects where object_name="EMPPK";
    +--------------------------------+--------------------------------------+
    | datetime(CREATED, 'unixepoch') | datetime(LAST_DDL_TIME, 'unixepoch') |
    +--------------------------------+--------------------------------------+
    | 2013-04-22 21:59:58 | 2013-05-24 15:29:00 |
    +--------------------------------+--------------------------------------+
    SQLRowCount returns 0
    1 rows fetched

    SQL> quit

    Cuando los elementos del servidor ODBC están en su rincón, tenemos la posibilidad de modificar la conectividad para un init.ora concreto de Oracle dg4odbc Cliente.

    Primero, el DBA precisa añadir una entrada de cliente TNS al siguiente fichero:

    $ORACLE_HOME/network/admin/tnsnames.ora

    La entrada TNS ha de ser afín al SID de la banco de información local. Asegúrese de que coincidan precisamente con el host configurado:

    sqlitec1 = (DESCRIPTION=
      (ADDRESS=
        (PROTOCOL=tcp)
        (HOST=1.2.3.4)
        (PORT=1524))
      (CONNECT_DATA=
        (SID=SQLitec1))
      (HS=OK))

    En el momento en que la entrada del cliente TNS está en su rincón, el escucha de la banco de información debe configurarse para comenzar el servicio ODBC en el momento en que sea preciso añadiendo una entrada al siguiente fichero:

    $ORACLE_HOME/network/admin/listener.ora

    El servicio nuevo se puede añadir a la lista de SID que existe:

        (SID_DESC=
          (SID_NAME=SQLitec1)
          (ORACLE_HOME=/home/oracle/Ora19)
          (PROGRAM=dg4odbc)
        )

    En este punto, reinicie el oyente:

    lsnrctl restart

    Con suerte, su oyente notificará sobre el nuevo SID de ODBC:

    Service "SQLitec1" has 1 instance(s).
      Instance "SQLitec1", status UNKNOWN, has 1 handler(s) for this service...

    Al final, cree un nuevo fichero init.ora que apunte a dg4odbc en la próxima localización:

    $ORACLE_HOME/hs/admin/initSQLitec1.ora

    Este fichero debe tener el próximo contenido:

    HS_FDS_CONNECT_INFO = SQLitec1
    HS_FDS_TRACE_LEVEL = 4

    La herramienta tnsping puede corroborar que el oyente conoce el servicio nuevo ODBC:

    $ $ORACLE_HOME/bin/tnsping sqlitec1
    
    TNS Ping Utility for Linux: Version 19.0.0.0.0 - Production on 09-JUL-2021 12:18:01
    
    Copyright (c) 1997, 2020, Oracle.  All rights reserved.
    
    Attempting to contact (description=(address=(protocol=tcp)(host=1.2.3.4)(port=1521))(connect_data=(sid=SQLitec1)))
    OK (0 msec)

    El DBA en este momento está ya listo para hacer un link de banco de información para una prueba de conectividad:

    $ $ORACLE_HOME/bin/sqlplus '/ as sysdba'
    
    SQL*Agregado: Release 19.0.0.0.0 - Production on Thu Jul 8 13:45:19 2021
    Version 19.3.0.0.0
    
    Copyright (c) 1982, 2019, Oracle.  All rights reserved.
    
    
    Connected to:
    Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
    Version 19.3.0.0.0
    
    SQL> create database backlink lite_c1 connect to nouser identified by nopass using 'sqlitec1';
    
    Database backlink created.
    
    SQL> select count
    

    Una versión anterior de gawk en una plataforma de 32 bits permitía marcas de tiempo de época negativas que se remontaban a diciembre de 1901 (tenga en cuenta que estas horas se expresan en relación con la zona horaria local, en este caso CST):

    $ ./strftime.gawk -2147483648 0 2147483647
    1901/12/13 14:45:52
    1969/12/31 18:00:00
    2038/01/18 21:14:07

    Las versiones más nuevas de gawk no permiten marcas de tiempo de época negativas (curiosamente, el awk busybox moderno no comparte esta limitación):

    $ ./strftime.gawk -2147483648
    gawk: ./strftime.gawk:2: fatal: strftime: second argument less than 0 or too big for time_t

    Los tiempos máximos que pueden expresarse usando gawk y transferirse fácilmente a Oracle en un sistema de 64 bits parecen ser:

    $ ./strftime.gawk 0 253402322399 67767976233554395
    1969/12/31 18:00:00
    9999/12/31 23:59:59
    2147483647/12/31 23:59:52

    Esta situación está documentada principalmente en la wiki para el año 2038.

    Oracle tiene un sitio web con capacidades de conversión para traducir Oracle DATE Ingrese la hora de UNIX. Tenga en cuenta que he ajustado los tiempos mínimo / máximo, el límite inferior a los resultados anteriores y el límite superior al último segundo del año 9999, ya que es seguro hacerlo en la era UNIX de 64 bits. A continuación, presento una versión modificada de esta función de conversión que devuelve los valores mínimo / máximo cuando se desborda y no es un error:

    CREAR O REEMPLAZAR LA FUNCIÓN date_to_unixts (oracle_date IN DATE) RETURN PLS_INTEGER IS unix_epoch DATE: = TO_DATE ('1970101000000', 'AAAAMMDDHH24MISS'); date_max DATUM: = AU_DATE ('20380101000000', 'AAAAMMDDHH24MISS'); min_date FECHA: = TO_DATE ('19030101000000', 'AAAAMMDDHH24MISS'); unix_ts PLS_INTEGER; INICIO SI oracle_date> from all_objects@lite_c1;

    COUNTUna versión anterior de gawk en una plataforma de 32 bits permitía marcas de tiempo de época negativas que se remontaban a diciembre de 1901 (tenga en cuenta que estas horas se expresan en relación con la zona horaria local, en este caso CST):

    $ ./strftime.gawk -2147483648 0 2147483647
    1901/12/13 14:45:52
    1969/12/31 18:00:00
    2038/01/18 21:14:07

    Las versiones más nuevas de gawk no permiten marcas de tiempo de época negativas (curiosamente, el awk busybox moderno no comparte esta limitación):

    $ ./strftime.gawk -2147483648
    gawk: ./strftime.gawk:2: fatal: strftime: second argument less than 0 or too big for time_t

    Los tiempos máximos que pueden expresarse usando gawk y transferirse fácilmente a Oracle en un sistema de 64 bits parecen ser:

    $ ./strftime.gawk 0 253402322399 67767976233554395
    1969/12/31 18:00:00
    9999/12/31 23:59:59
    2147483647/12/31 23:59:52

    Esta situación está documentada principalmente en la wiki para el año 2038.

    Oracle tiene un sitio web con capacidades de conversión para traducir Oracle DATE Ingrese la hora de UNIX. Tenga en cuenta que he ajustado los tiempos mínimo / máximo, el límite inferior a los resultados anteriores y el límite superior al último segundo del año 9999, ya que es seguro hacerlo en la era UNIX de 64 bits. A continuación, presento una versión modificada de esta función de conversión que devuelve los valores mínimo / máximo cuando se desborda y no es un error:

    CREAR O REEMPLAZAR LA FUNCIÓN date_to_unixts (oracle_date IN DATE) RETURN PLS_INTEGER IS unix_epoch DATE: = TO_DATE ('1970101000000', 'AAAAMMDDHH24MISS'); date_max DATUM: = AU_DATE ('20380101000000', 'AAAAMMDDHH24MISS'); min_date FECHA: = TO_DATE ('19030101000000', 'AAAAMMDDHH24MISS'); unix_ts PLS_INTEGER; INICIO SI oracle_date>
    --------
    23699

    Visualizaciones:

    DML básico en este momento se puede realizar con bases de datos Oracle SQLite:

    SQL> delete from all_objects@lite_c1;
    
    23699 rows deleted.
    
    SQL> commit;
    
    Commit complete.

    Al insertar de nuevo desde la visión complicada ALL_OBJECTS ...

    SQL> insert into all_objects@lite_c1
      select
      OWNER                         --  1
    , OBJECT_NAME                   --  2
    , SUBOBJECT_NAME                --  3
    , OBJECT_ID                     --  4
    , DATA_OBJECT_ID                --  5
    , OBJECT_TYPE                   --  6
    , date_to_unixts(CREATED)       --  7
    , date_to_unixts(LAST_DDL_TIME) --  8
    , TIMESTAMP                     --  9
    , STATUS                        -- 10
    , TEMPORARY                     -- 11
    , GENERATED                     -- 12
    , SECONDARY                     -- 13
      from sys.all_objects;

    ... suceden fallos repetidos, aun si muchas líneas incorrectas son sustituidas por NULL:

      *
    ERROR at line 8:
    ORA-02070: database LITE_C1 does not support DECODE in this context
      *
    ERROR at line 9:
    ORA-02070: database LITE_C1 does not support operator 169 in this context
      *
    ERROR at line 10:
    ORA-02070: database LITE_C1 does not support operator 169 in this context
      *
    ERROR at line 11:
    ORA-02070: database LITE_C1 does not support TO_CHAR in this context
      *
    ERROR at line 12:
    ORA-02070: database LITE_C1 does not support DECODE in this context
      *
    ERROR at line 13:
    ORA-02070: database LITE_C1 does not support DECODE in this context

    Pegar desde vistas complicadas semeja ser un inconveniente real para la conectividad de la banco de información; Esta actividad se amolda mejor al procedimiento de transferencia CSV de la sección previo.

    El DML primitivo semeja ser servible:

    SQL> insert into all_objects@lite_c1 (OWNER,OBJECT_NAME) values ('foo','bar');
    
    1 row created.
    
    SQL> commit;
    
    Commit complete.

    Los datos insertados por Oracle se muestran en SQLite:

    SQL> select * from all_objects@lite_c1;
    
    OWNER OBJECT_NAME ...
    ----- ----------- ...
    foo   bar         ...

    Oracle asimismo puede reportar una versión recóndita de SQLite si se creó como una vista:

    sqlite> create view my_version as select sqlite_version();
    sqlite> select * from my_version;
    3.36.0

    Oracle puede seleccionar esta vista:

    SQL> select * from my_version@lite_c1;
    
    sqlite_version()
    ----------------
    3.7.17
    
    SQL> select version from v$instance;
    
    VERSION
    -----------------
    19.0.0.0.0

    En RedHat 8 está el caparazón archivo El comando puede reportar la versión del último SQLite que escribió en la banco de información:

    $ archivo /home/oracle/orasys.db3
    
    /home/oracle/orasys.db3: SQLite 3.x database, last written using SQLite version 3036000

    La instancia de ODBC emplea una versión previo de SQLite y la humillación es aparente una vez que ODBC ocupa DML:

    $ archivo /home/oracle/orasys.db3
    
    /home/oracle/orasys.db3: SQLite 3.x database, last written using SQLite version 3026000

    ODBC asimismo semeja fallar con ciertos SQL gracias a los links de devolución de llamada en la implementación ODBC de SQLite con el fallo:

    ORA-02025: all tables in the SQL statement must be at the remote database

    De todos modos, esta plataforma de trabajo ODBC no es sólida.

    PHP al salve

    Tan frágil como es ODBC, PHP es del mismo modo fiable. PHP puede conducir de manera fácil LONG Géneros de datos, solo un desarrollo de cliente está activo y, aparte de su situación habitual como motor de servidor web, se ejecuta como intérprete de shell.

    Mira el previo ALL_VIEWS que contenía un LONG Pilar:

    SQL> desc all_views
     Name					   Null?    Type
     ----------------------------------------- -------- --------------
     OWNER					   NOT NULL VARCHAR2(30)
     VIEW_NAME				   NOT NULL VARCHAR2(30)
     TEXT_LENGTH					    NUMBER
     TEXT						    LONG
     TYPE_TEXT_LENGTH				    NUMBER
     TYPE_TEXT					    VARCHAR2(4000)
     OID_TEXT_LENGTH				    NUMBER
     OID_TEXT					    VARCHAR2(4000)
     VIEW_TYPE_OWNER				    VARCHAR2(30)
     VIEW_TYPE					    VARCHAR2(30)
     SUPERVIEW_NAME 				    VARCHAR2(30)
     EDITIONING_VIEW				    VARCHAR2(1)

    Podríamos añadir TEXT Columna para esta tabla:

    $ sqlite3 orasys.db3 
    SQLite version 3.36.0 2021-06-18 18:36:39
    Entrar ".help" for usage hints.
    sqlite>   create table all_views (
       ...>   OWNER            TEXT --  1 *
       ...> , VIEW_NAME        TEXT --  2
       ...> , TEXT_LENGTH      NUM  --  3
       ...> , text text
       ...> , TYPE_TEXT_LENGTH NUM  --  5 *
       ...> , TYPE_TEXT        TEXT --  6
       ...> , OID_TEXT_LENGTH  NUM  --  7
       ...> , OID_TEXT         TEXT --  8
       ...> , VIEW_TYPE_OWNER  TEXT --  9
       ...> , VIEW_TYPE        TEXT -- 10
       ...> , SUPERVIEW_NAME   TEXT -- 11
       ...> , EDITIONING VIEW  TEXT -- 12
       ...>   );

    Entonces, un script fácil puede copiar la tabla de cambiantes vinculantes línea por línea. Ahora presento 2 ediciones, una con la clase PHP SQLite nativa y la otra con la clase de abstracción PHP Data Objects (PDO) genérica. La versión PDO semeja un tanto mucho más rápida.

    SQLite originario de PHP

    $ cat dump_all_views-sqlite.php 
    #!/usr/local/bin/php -f
    exec('BEGIN;');
    
    $insert = $litedb->prepare($q);
    
    while($values =
      oci_fetch_array($curs, OCI_NUM + OCI_RETURN_NULLS + OCI_RETURN_LOBS))
      
    
    $litedb->exec('COMMIT;');
    
    oci_free_statement($curs);
    
    oci_close($conn);
    
    ?>

    PHP PDO SQLite

    $ cat dump_all_views-PDO.php
    #!/usr/local/bin/php -f
    beginTransaction();
    
    $insert = $litedb->prepare($sql);
    
    while($values =
      oci_fetch_array($curs, OCI_NUM + OCI_RETURN_NULLS + OCI_RETURN_LOBS))
        $insert->execute($values);
    
    $litedb->commit();
    
    oci_free_statement($curs);
    
    oci_close($conn);
    
    ?>

    Las cambiantes de link son considerablemente más esenciales para Oracle que SQLite. Oracle tiene un "caché de biblioteca" que puede advertir y "investigar sin inconvenientes" SQL idéntico, que es considerablemente más veloz que el SQL sin caché que precisa ser "analizado duro". Aparte de los resultados positivos de desempeño de una declaración SQL de enorme volumen, las cambiantes de link asimismo brindan alguna protección contra la "inyección SQL", un beneficio que probablemente compartirá SQLight. Los scripts de SQL Texttract precedentes empleaban cambiantes vinculantes.

    Las cambiantes de link SQLite tienen la posibilidad de ser de tipo Oracle (: the_owner en los scripts precedentes) o de tipo Sybase / SQL Server (?,?,? ...). Estos últimos están vinculados por una situación numérica y los primeros por un nombre explícito. ¿Empieza la clase SQLite? situaciones numéricas en 1, no en cero.

    Ahora se expone una ejecución de exhibe que quita esta matriz (tenga presente que pasar la contraseña así la hace aparente en /proc/*/environque no es buena práctica):

    $ export DBUSER=fishecj \
      TNS='(description=(address=(protocol=tcp)(host=1.2.3.4)(port=1521))(connect_data=(sid=orcl)))'
    $ stty -echo; read DBPASS; stty echo; echo ''
    
    $ DBPASS="$DBPASS" ./dump_all_views.php SYS

    El control de transferencias semeja prosperar el desempeño de SQLite pues el script hace bastante corre mucho más retardado si el beginTransaction y commit siendo eliminado.

    En este momento el contenido terminado de Oracle ALL_VIEWS para el usuario de sys se puede observar en SQLite:

    $ sqlite3 orasys.db3 
    SQLite version 3.36.0 2021-06-18 18:36:39
    Entrar ".help" for usage hints.
    
    sqlite> select count
    

    Una versión anterior de gawk en una plataforma de 32 bits permitía marcas de tiempo de época negativas que se remontaban a diciembre de 1901 (tenga en cuenta que estas horas se expresan en relación con la zona horaria local, en este caso CST):

    $ ./strftime.gawk -2147483648 0 2147483647
    1901/12/13 14:45:52
    1969/12/31 18:00:00
    2038/01/18 21:14:07

    Las versiones más nuevas de gawk no permiten marcas de tiempo de época negativas (curiosamente, el awk busybox moderno no comparte esta limitación):

    $ ./strftime.gawk -2147483648
    gawk: ./strftime.gawk:2: fatal: strftime: second argument less than 0 or too big for time_t

    Los tiempos máximos que pueden expresarse usando gawk y transferirse fácilmente a Oracle en un sistema de 64 bits parecen ser:

    $ ./strftime.gawk 0 253402322399 67767976233554395
    1969/12/31 18:00:00
    9999/12/31 23:59:59
    2147483647/12/31 23:59:52

    Esta situación está documentada principalmente en la wiki para el año 2038.

    Oracle tiene un sitio web con capacidades de conversión para traducir Oracle DATE Ingrese la hora de UNIX. Tenga en cuenta que he ajustado los tiempos mínimo / máximo, el límite inferior a los resultados anteriores y el límite superior al último segundo del año 9999, ya que es seguro hacerlo en la era UNIX de 64 bits. A continuación, presento una versión modificada de esta función de conversión que devuelve los valores mínimo / máximo cuando se desborda y no es un error:

    CREAR O REEMPLAZAR LA FUNCIÓN date_to_unixts (oracle_date IN DATE) RETURN PLS_INTEGER IS unix_epoch DATE: = TO_DATE ('1970101000000', 'AAAAMMDDHH24MISS'); date_max DATUM: = AU_DATE ('20380101000000', 'AAAAMMDDHH24MISS'); min_date FECHA: = TO_DATE ('19030101000000', 'AAAAMMDDHH24MISS'); unix_ts PLS_INTEGER; INICIO SI oracle_date> from all_views;
    3812

    sqlite> select text from all_views where view_name="ALL_VIEWS";
    select u.name, o.name, v.textlength, v.text, t.typetextlength, t.typetext,
    t.oidtextlength, t.oidtext, t.typeowner, t.typename,
    decode(bitand(v.property, 134217728), 134217728,
    (select sv.name from superobj$ h, "_CURRENT_EDITION_OBJ" sv
    where h.subobj# = o.obj# and h.superobj# = sv.obj#), null),
    decode(bitand(v.property, 32), 32, 'Y', 'N'),
    decode(bitand(v.property, 16384), 16384, 'Y', 'N')
    from sys."_CURRENT_EDITION_OBJ" o, sys.view$ v, sys.usuario$ u, sys.typed_view$ t
    where o.obj# = v.obj#
    and o.obj# = t.obj#(+)
    and o.owner# = u.usuario#
    and (o.owner# = userenv('SCHEMAID')
    or o.obj# in
    (select oa.obj#
    from sys.objauth$ oa
    where oa.grantee# in ( select kzsrorol
    from x$kzsro
    )
    )
    or /* usuario has system privileges */
    exists (select null from v$enabledprivs
    where priv_number in (-45 /* LOCK ANY TABLE */,
    -47 /* SELECT ANY TABLE */,
    -48 /* INSERT ANY TABLE */,
    -49 /* UPDATE ANY TABLE */,
    -50 /* DELETE ANY TABLE */)
    )
    )

    Conclusión

    Muchos usuarios tienen altas solicitudes de bases de datos heredadas que no se tienen la posibilidad de cumplir de manera fácil gracias a inconvenientes de escalabilidad o licencias (la licencia minorista para bases de datos Oracle cuesta $ 47,500 por núcleo de únidad central de procesamiento). SQLite es una alternativa para calmar la carga de estos individuos, y la búsqueda de esa opción inspiró este producto.

    Precisamente, existen algunas características en SQLite que lo distinguen drásticamente de los ámbitos RDBMS habituales. La extrema tolerancia de la sintaxis, la fluidez en la escritura y la carencia de privilegios sorprenden a varios clientes.

    Asimismo está lejos de ser bien difícil localizar varios DBA que jamás hayan oído charlar de SQLite. Más allá de que normalmente está "bajo el radar" para la administración de TI, se conoce que los programadores (ab) lo utilizan por el hecho de que se sienten frustrados con las bases de datos corporativas formales que cumplen con SOX. Conforme estos programadores avanzan, los guardes de datos subterráneos con frecuencia no reciben la atención que meritan.

    La ubicuidad de SQLite en teléfonos móviles inteligentes y otros modelos electrónicos de consumo asimismo es espantosa. Desde este criterio, es una herramienta de supervisión importante con peligrosas implicaciones para la intimidad.

    Es preferible para una organización de TI estar familiarizada con SQLite que no, y para los auditores que son siendo conscientes de los riesgos del empleo conveniente y la exfiltración de datos. La creencia en el control de ingreso en un RDBMS cliente / servidor puede disolverse con una mala experiencia con SQLite; Con suerte, este producto evitará esa experiencia para muchos.

    Fuente original

    You may also like