#Compilador

0 Seguidores · 8 Publicaciones

La herramienta que compila el código fuente hacia otra forma de código ejecutable.

InterSystems Official Jose-Tomas Salvador · dic 16, 2024

Las primeras versiones preliminares para desarrolladores de la plataforma de datos InterSystems IRIS®, InterSystems IRIS® for Health y HealthShare® Health Connect 2025.1 se han publicado en el sitio de versiones preliminares para desarrolladores del WRC.  Los contenedores se pueden encontrar en nuestro registro de contenedores y están etiquetados como latest-preview.

0
0 70
Artículo Kurro Lopez · jun 16, 2020 9m read

En mi anterior artículo, revisamos los posibles casos de uso para macros, así que pasemos ahora a un ejemplo más completo de usabilidad de macros. En este artículo diseñaremos y crearemos un sistema de registro.

Sistema de registro

El sistema de registro es una herramienta útil para monitorear el trabajo de una aplicación que ahorra mucho tiempo durante la depuración y el monitoreo. Nuestro sistema constaría de dos partes:

  • Clase de almacenamiento (para registros de anotaciones)
  • Conjunto de macros que agregan automáticamente un nuevo registro al registro

Clase de almacenamiento

Vamos a crear una tabla de lo que necesitamos almacenar y especificar cuándo se pueden obtener estos datos, durante la compilación o en tiempo de ejecución. Esto será necesario cuando trabaje en la segunda parte del sistema: macros, donde buscaremos tener tantos detalles registrables como sea posible durante la compilación:

InformaciónObtenido durante
Tipo de eventoCompilación
Nombre de claseCompilación
Nombre del métodoCompilación
Argumentos pasados ​​a un métodoCompilación
Número de línea en el código fuente de clsRuntime
Número de línea en el código int generadoRuntime
Nombre de usuarioRuntime
Date/TimeRuntime
MensajeRuntime
direccion IPRuntime

Vamos a crear una clase App.Log que contenga las propiedades de la tabla anterior. Cuando se crea un objeto App.Log, las propiedades de UserName, TimeStamp y ClientIPAddress se completan automáticamente.

App.Log class:

Class App.Log Extends %Persistent
{

/// Type of event Property EventType As %String(MAXLEN = 10, VALUELIST = ",NONE,FATAL,ERROR,WARN,INFO,STAT,DEBUG,RAW") [ InitialExpression = "INFO" ];

/// Name of class, where event happened Property ClassName As %String(MAXLEN = 256);

/// Name of method, where event happened Property MethodName As %String(MAXLEN = 128);

/// Line of int code Property Source As %String(MAXLEN = 2000);

/// Line of cls code Property SourceCLS As %String(MAXLEN = 2000);

/// Cache user Property UserName As %String(MAXLEN = 128) [ InitialExpression = {$username} ];

/// Arguments' values passed to method Property Arguments As %String(MAXLEN = 32000, TRUNCATE = 1);

/// Date and time Property TimeStamp As %TimeStamp [ InitialExpression = {$zdt($h, 3, 1)} ];

/// User message Property Message As %String(MAXLEN = 32000, TRUNCATE = 1);

/// User IP address Property ClientIPAddress As %String(MAXLEN = 32) [ InitialExpression = {..GetClientAddress()} ];

/// Determine user IP address ClassMethod GetClientAddress() { // %CSP.Session source is preferable #dim %request As %CSP.Request If ($d(%request)) { Return %request.CgiEnvs("REMOTE_ADDR") } Return $system.Process.ClientIPAddress() } }

 

Macros de registro

Por lo general, las macros se almacenan en archivos * .inc separados que contienen sus definiciones. Los archivos necesarios se pueden incluir en clases usando el comando Include MacroFileName, que en este caso se verá de la siguiente manera: Include App.LogMacro.
 
Para comenzar, definamos la macro principal que el usuario agregará al código de su aplicación:

#define LogEvent(%type, %message) Do ##class(App.Log).AddRecord($$$CurrentClass, $$$CurrentMethod, $$$StackPlace, %type, $$$MethodArguments, %message)

Esta macro acepta dos argumentos de entrada: Tipo de evento y Mensaje. El usuario define el argumento Mensaje, pero el parámetro Tipo de evento requerirá macros adicionales con diferentes nombres que identificarán automáticamente el tipo de evento:

#define LogNone(%message)         $$$LogEvent("NONE", %message)
#define LogError(%message)        $$$LogEvent("ERROR", %message)
#define LogFatal(%message)        $$$LogEvent("FATAL", %message)
#define LogWarn(%message)         $$$LogEvent("WARN", %message)
#define LogInfo(%message)         $$$LogEvent("INFO", %message)
#define LogStat(%message)         $$$LogEvent("STAT", %message)
#define LogDebug(%message)        $$$LogEvent("DEBUG", %message)
#define LogRaw(%message)          $$$LogEvent("RAW", %message)

Por lo tanto, para realizar el registro, el usuario solo necesita colocar la macro $$$LogError("Additional message") en el código de la aplicación.
Todo lo que necesitamos hacer ahora es definir las macros $$$CurrentClass, $$$CurrentMethod, $$$StackPlace, $$$MethodArguments.Comencemos con las tres primeras:

#define CurrentClass     ##Expression($$$quote(%classname))
#define CurrentMethod    ##Expression($$$quote(%methodname))
#define StackPlace       $st($st(-1),"PLACE")

%classname, %methodname las variables se describen en la documentacion. La función $stack devuelve el número de línea del código INT. Para convertirlo en un número de línea CLS, podemos usar este código.

Usemos el paquete %Dictionary para obtener una lista de argumentos de métodos y sus valores. Contiene toda la información sobre las clases, incluidas las descripciones de los métodos. Estamos particularmente interesados ​​en la clase %Dictionary.CompiledMethod y su propiedad FormalSpecParsed, que es una lista:

$lb($lb("Name","Classs","Type(Output/ByRef)","Default value "),...)

correspondiente a la firma del método. Por ejemplo:

ClassMethod Test(a As %Integer = 1, ByRef b = 2, Output c)

tendrá el siguiente valor FormalSpecParsed:

$lb(
$lb("a","%Library.Integer","","1"),
$lb("b","%Library.String","&","2"),
$lb("c","%Library.String","*",""))

Necesitamos que la macro $$$MethodArguments se expanda en el siguiente código (para el método Test):

"a="_$g(a,"Null")_"; b="_$g(b,"Null")_"; c="_$g(c,"Null")_";"

Para lograr esto, tenemos que hacer lo siguiente durante la compilación:

  1. Obtenga un nombre de clase y un nombre de método
  2. Abra una instancia correspondiente de la clase %Dictionary.CompiledMethod y obtenga su propiedad FormalSpec
  3. Conviértalo en una línea de código fuente

Agreguemos los métodos correspondientes a la clase App.Log:

ClassMethod GetMethodArguments(ClassName As %String, MethodName As %String) As %String
{
    Set list = ..GetMethodArgumentsList(ClassName,MethodName)
    Set string = ..ArgumentsListToString(list)
    Return string
}

ClassMethod GetMethodArgumentsList(ClassName As %String, MethodName As %String) As %List { Set result = "" Set def = ##class(%Dictionary.CompiledMethod).%OpenId(ClassName _ "||" _ MethodName) If ($IsObject(def)) { Set result = def.FormalSpecParsed } Return result }

ClassMethod ArgumentsListToString(List As %List) As %String { Set result = "" For i=1:1:$ll(List) { Set result = result _ $$$quote($s(i>1=0:"",1:"; ") _ $lg($lg(List,i))"=") _ "$g(" _ $lg($lg(List,i)) _ ","$$$quote(..#Null)")_" _$s(i=$ll(List)=0:"",1:$$$quote(";")) } Return result }


Ahora definamos la macro $$$MethodArguments como:

#define MethodArguments ##Expression(##class(App.Log).GetMethodArguments(%classname,%methodname))

Caso de uso

A continuación, creemos una clase App.Use con un método de prueba para demostrar las capacidades del sistema de registro:

Include App.LogMacro
Class App.Use [ CompileAfter = App.Log ]
{
/// Do ##class(App.Use).Test()
ClassMethod Test(a As %Integer = 1, ByRef b = 2)
{
    $$$LogWarn("Text")
}
}

Como resultado, la macro $$$LogWarn("Text") en el código int se convierte en la siguiente línea:

Do ##class(App.Log).AddRecord("App.Use","Test",$st($st(-1),"PLACE"),"WARN","a="_$g(a,"Null")_"; b="_$g(b,"Null")_";", "Text")

La ejecución de este código creará un nuevo registro de App.Log:

Mejoras

Después de haber creado un sistema de registro, aquí hay algunas ideas de mejora:

  • En primer lugar, existe la posibilidad de procesar argumentos de tipo objeto ya que nuestra implementación actual solo registra objetos oref.
  • Segundo, una llamada para restaurar el contexto de un método a partir de valores de argumentos almacenados.

Procesamiento de argumentos de tipo objeto

La línea que pone un valor de argumento en el registro se genera en el método ArgumentsListToString y tiene este aspecto:

"_$g(" _ $lg($lg(List,i)) _ ","_$$$quote(..#Null)_")_"

Realicemos una refactorización y muévala a un método GetArgumentValue separado que acepte un nombre y clase de variable (todo lo que sabemos de FormalSpecParsed) y genere un código que convertirá la variable en una línea. Usaremos el código existente para los tipos de datos, y los objetos se convertirán en JSON con la ayuda de los métodos SerializeObject (para llamar desde el código de usuario) y WriteJSONFromObject (para convertir un objeto en JSON):

ClassMethod GetArgumentValue(Name As %String, ClassName As %Dictionary.CacheClassname) As %String
{
    If $ClassMethod(ClassName, "%Extends", "%RegisteredObject") {
        // it's an object
        Return "_##class(App.Log).SerializeObject("_Name _ ")_"
    } Else {
        // it's a datatype
        Return "_$g(" _ Name _ ","_$$$quote(..#Null)_")_"
    }
}

ClassMethod SerializeObject(Object) As %String { Return:'$IsObject(Object) Object Return ..WriteJSONFromObject(Object) }

ClassMethod WriteJSONFromObject(Object) As %String [ ProcedureBlock = 0 ] { Set OldIORedirected = ##class(%Device).ReDirectIO() Set OldMnemonic = ##class(%Device).GetMnemonicRoutine() Set OldIO = $io Try { Set Str=""

    //Redirect IO to the current routine - makes use of the labels defined below
    Use $io::("^"_$ZNAME)

    //Enable redirection
    Do ##class(%Device).ReDirectIO(1)

    Do ##class(%ZEN.Auxiliary.jsonProvider).%ObjectToJSON(Object)
} Catch Ex {
    Set Str = ""
}

//Return to original redirection/mnemonic routine settings
If (OldMnemonic '= "") {
    Use OldIO::("^"_OldMnemonic)
} Else {
    Use OldIO
}
Do ##class(%Device).ReDirectIO(OldIORedirected)

Quit Str

// Labels that allow for IO redirection
// Read Character - we don't care about reading

rchr(c) Quit // Read a string - we don't care about reading rstr(sz,to) Quit // Write a character - call the output label wchr(s) Do output($char(s)) Quit // Write a form feed - call the output label wff() Do output($char(12)) Quit // Write a newline - call the output label wnl() Do output($char(13,10)) Quit // Write a string - call the output label wstr(s) Do output(s) Quit // Write a tab - call the output label wtab(s) Do output($char(9)) Quit // Output label - this is where you would handle what you actually want to do. // in our case, we want to write to Str output(s) Set Str = Str_s Quit }

Una entrada de registro con un argumento de tipo objeto se ve así:

Restaurando el contexto

La idea de este método es hacer que todos los argumentos estén disponibles en el contexto actual (principalmente en la terminal, para la depuración). Para este fin, podemos usar el parámetro del método ProcedureBlock. Cuando se establece en 0, todas las variables declaradas dentro de dicho método permanecerán disponibles al salir del método. Nuestro método abrirá un objeto de la clase App.Log y deserializará la propiedad Argumentos.

ClassMethod LoadContext(Id) As %Status [ ProcedureBlock = 0 ]
{
    Return:'..%ExistsId(Id) $$$OK
    Set Obj = ..%OpenId(Id)
    Set Arguments = Obj.Arguments
    Set List = ..GetMethodArgumentsList(Obj.ClassName,Obj.MethodName)
    For i=1:1:$Length(Arguments,";")-1 {
        Set Argument = $Piece(Arguments,";",i)
        Set @$lg($lg(List,i)) = ..DeserializeObject($Piece(Argument,"=",2),$lg($lg(List,i),2))
    }
    Kill Obj,Arguments,Argument,i,Id,List
}

ClassMethod DeserializeObject(String, ClassName) As %String { If $ClassMethod(ClassName, "%Extends", "%RegisteredObject") { // it's an object Set st = ##class(%ZEN.Auxiliary.jsonProvider).%ConvertJSONToObject(String,,.obj) Return:$$$ISOK(st) obj } Return String }

Así es como se ve en la terminal:

>zw
>do ##class(App.Log).LoadContext(2)
>zw

a=1 b=<OBJECT REFERENCE>[2@%ZEN.proxyObject]

>zw b b=<OBJECT REFERENCE>[2@%ZEN.proxyObject] +----------------- general information --------------- | oref value: 2 | class name: %ZEN.proxyObject | reference count: 2 +----------------- attribute values ------------------ | %changed = 1 | %data("prop1") = 123 | %data("prop2") = "abc" | %index = ""

¿Que sigue?

La mejora potencial clave es agregar otro argumento a la clase de registro con una lista arbitraria de variables creadas dentro del método.

Conclusiones

Las macros pueden ser bastante útiles para el desarrollo de aplicaciones.

Preguntas

¿Hay alguna manera de obtener el número de línea durante la compilación?

Links

1
0 242
Pregunta Paco Cadenas · dic 14, 2022

Hola!

Entiendo no hay automatismo para actualizar código antiguo que imbrica con "puntitos" transformándolo a código con llaves "{ }", creo que hacer un parser de este tipo sería complejo por situaciones como esta :

Alguien sabe si este código es equivalente ?

VERSION CON PUNTITOS
 Use fic

Read *R:20 Else  Do  Quit    ;;;;  comando else aplicado a read.
  . Use 0 Write !!!,"Temps expirat."
 If $c(R)="a" d
  . Use 0 Write !!!,"Ha leido una letra a"
  . Quit
 
VERSION CON LLAVES
 Use fic
 Read *R:20
 If $Test {
Use 0 Write !!!,"Ha leido un carácter"
Quit
 }
 Else {
Use 0 Write !!!,"Temps expirat."
 }
 

3
0 133
Comentarios Mathew Lambert · sep 22, 2021

Sobreescribiendo el método Read (que tiene un tipo de retorno %CacheString) en una nueva clase que hereda de %Stream.FileCharacter, se obtiene un error de compilacion informando que el tipo de retorno es incorrecto y ha de ser Binary, aun cuando matchea la firma del padre.

Mirando la global de codigo compilado vemos:

^oddCOM("%Stream.FileBinary","m","Read",42)="%Library.Binary"

Despues de más investigaciones encontramos que hay un método generator que mira la definicion de clase OdbcType.

Seteandolo a LONGVARCHAR nos da:

^oddCOM("User.CStream","m","Read",42)="%Library.String"

0
0 113
Pregunta Daniel Aguilar · sep 8, 2020

Buenas tardes estamos probando a actualizar una versión 2014 a la 2018 para posteriormente actualizar a la versión 2019 y nos hemos encontrado con este problema al pasar de la 2014 a la 2018.

Tras actualizar si ejecutamos una Query de actualización desde el portal nos da el siguiente error:

He comprobado que si desde el Studio compilo la clase este error desaparece. He podido comprobar que en la clase .int que contiene la compilada tiene un parámetro menos %ouid

4
0 174
Artículo Kurro Lopez · mayo 17, 2020 7m read

En este artículo me gustaría contarle acerca de las macros en InterSystems Caché. Una macro es un nombre simbólico que se reemplaza con un conjunto de instrucciones durante la compilación. Una macro puede "desplegarse" en varios conjuntos de instrucciones cada vez que se llama, dependiendo de los parámetros que se le pasen y los escenarios activados. Esto puede ser tanto código estático como el resultado de la ejecución de ObjectScript. Echemos un vistazo a cómo puede usarlos en su aplicación.

Compilación

Para empezar, veamos cómo se compila el código ObjectScript:

  1. El compilador de clases usa definiciones de clase para generar código MAC
  2. En algunos casos, el compilador usa clases como base para generar clases adicionales. Puede ver estas clases en el estudio, pero no debe cambiarlas. Esto sucede, por ejemplo, al generar clases que definen servicios web y clientes
  3. El compilador de clases también genera un descriptor de clase utilizado por Caché en tiempo de ejecución
  4. El preprocesador (también conocido como macro preprocesador, MPP) utiliza archivos INC y reemplaza las macros. Además, también procesa SQL incorporado en rutinas ObjectScript
  5. Todos estos cambios tienen lugar en la memoria; el código del usuario permanece sin cambios
  6. Después de eso, el compilador crea código INT para las rutinas de ObjectScript. Esta capa se conoce como código intermedio. Todo el acceso a los datos en este nivel se proporciona a través de globals
  7. El código INT es compacto y puede ser leído por un humano. Para verlo en el Studio, presione Ctrl + Shift + V.
  8. El código INT se usa para generar código OBJ
  9. El código OBJ es utilizado por la máquina virtual Caché. Una vez que se genera, el código CLS / MAC / INT ya no es necesario y puede eliminarse (por ejemplo, si queremos enviar un producto sin el código fuente)
  10. Si la clase es persistent, el compilador SQL creará las tablas SQL correspondientes

Macros

Como mencioné antes, una macro es un nombre simbólico que se reemplaza por el preprocesador con un conjunto de instrucciones. Una macro se define con la ayuda del comando #Define seguido del nombre de la macro (quizás con una lista de argumentos) y su valor:

#Define Macro[(Args)] [Value]

¿Dónde se pueden definir las macros? Ya sea en el código o en forma independiente en archivos INC que contiene solo macros. Los archivos necesarios se incluyen en las clases al comienzo de las definiciones de clase utilizando el comando Include MacroFileName - este es el método principal y preferido para incluir macros en clases. Las macros incluidas de esta manera se pueden usar en cualquier parte de una clase. Puedes usar el comando #Include MacroFileName para incluir un archivo INC con macros en rutinas MAC o el código de métodos de clase particulares.

Tenga en cuenta que los generadores de métodos requieren #Include dentro de su propio cuerpo si quieres usar macros en tiempo de compilación o uso de la palabra clave IncludeGenerator en una clase.

Para hacer que la macro esté disponible en el autocompletado de estudio, agregue /// en una línea anterior:

///
#Define Macro[(Args)] [Value]

Ejemplos

Ejemplo 1

Pasemos ahora a algunos ejemplos, y ¿por qué no comenzamos con el mensaje estándar "Hello, World!"? Código COS: 

Write "Hello, World!"

Crearemos una macro llamada HW que escribirá esta línea:

#define HW Write "Hello, World!"

Todo lo que necesitamos hacer ahora es escribir $$$HW ($$$ para llamar a la macro, luego su nombre):

ClassMethod Test()
{
     #define HW Write "Hello, World!"
     $$$HW
}

Se convertirá en el siguiente código INT durante la compilación:

zTest1() public {
     Write "Hello, World!" }

El siguiente texto se mostrará en la terminal cuando se llame a este método:

Hello, World!

Ejemplo 2

Usemos variables en el siguiente ejemplo:

ClassMethod Test2()
{
     #define WriteLn(%str,%cnt) For ##Unique(new)=1:1:%cnt { ##Continue
         Write %str,! ##Continue
     }
 $$$WriteLn("Hello, World!",5)

}

Aquí la cadena %str está escrita %cnt veces. Los nombres de las variables deben comenzar con %. El comando ##Unique(new) crea una nueva variable única en el código generado, mientras que el comando ##Continue nos permite continuar definiendo la macro en la siguiente línea. Este código se convierte en el siguiente código INT:

zTest2() public {
     For %mmmu1=1:1:5 {
         Write "Hello, World!",!
     } }

El terminal mostrará lo siguiente:

Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!

 

Ejemplo 3

Pasemos a los ejemplos más complejos. El operador ForEach puede ser muy útil para iterar a través de globals, creémoslo:

ClassMethod Test3()
{
    #define ForEach(%key,%gn) Set ##Unique(new)=$name(%gn) ##Continue
    Set %key="" ##Continue
    For { ##Continue
        Set %key=$o(@##Unique(old)@(%key)) ##Continue
        Quit:%key=""
#define EndFor    }

   Set ^test(1)=111
   Set ^test(2)=222
   Set ^test(3)=333
   
   $$$EachFor(key,^test)
       Write "key: ",key,!
       Write "value: ",^test(key),!
   $$$EndFor

}

Así es como se ve en el código INT:

zTest3() public {
       Set ^test(1)=111
       Set ^test(2)=222
       Set ^test(3)=333
       Set %mmmu1=$name(^test)
       Set key=""
       For {
           Set key=$o(@%mmmu1@(key))
           Quit:key=""
           Write "key: ",key,!
           Write "value: ",^test(key),!
       } }

¿Qué está pasando en estas macros?

  1. Escribe el nombre del global a una nueva variable %mmmu1 (función $name )
  2. La clave asume el valor inicial de cadena vacía
  3. Comienza el ciclo de iteración
  4. El siguiente valor de la clave se asigna usando las funciones indirection y $order
  5. Post-condition se utiliza para verificar si la clave ha asumido un valor "" ; si es así, la iteración se completa y el ciclo termina
  6. Se ejecuta código de usuario arbitrario, en este caso, salida de clave y valor
  7. Se cierra el ciclo

El terminal muestra lo siguiente cuando se llama a este método:

key: 1
value: 111
key: 2
value: 222
key: 3
value: 333

Si está utilizando listas y matrices heredadas de la clase %Collection.AbstractIterator, puede escribir un iterador similar para ello.

Ejemplo 4

Otra capacidad de las macros es la ejecución de código arbitrario de ObjectScript en la etapa de compilación y la sustitución de sus resultados en lugar de una macro. Creemos una macro para mostrar el tiempo de compilación:

ClassMethod Test4()
{
      #Define CompTS ##Expression("""Compiled: " _ $ZDATETIME($HOROLOG) _ """,!")
      Write $$$CompTS
}

Que se transforma en el siguiente código INT:

zTest4() public {
      Write "Compiled: 18.10.2016 15:28:45",! }

El terminal mostrará la siguiente línea cuando se llame a este método:

Compiled: 18.10.2015 15:28:45

##Expression ejecuta el código y sustituye el resultado. Los siguientes elementos del lenguaje ObjectScript se pueden utilizar para la entrada:

  • Strings: "abc"
  • Routines: $$Label^Routine
  • Class methods: ##class(App.Test).GetString()
  • Funciones COS: $name(var)
  • Y combinaciones de estos elementos

Ejemplo 5

Directivas del pre procesador #If, #ElseIf, #Else, #EndIf se utilizan para seleccionar el código fuente durante la compilación, según el valor de la expresión que sigue una directiva. Por ejemplo, este método:

ClassMethod Test5()
{
    #If $SYSTEM.Version.GetNumber()="2016.2.0" && $SYSTEM.Version.GetBuildNumber()="736"
        Write "You are using the latest released version of Caché"
    #ElseIf $SYSTEM.Version.GetNumber()="2017.1.0"
        Write "You are using the latest beta version of Caché"
    #Else
        Write "Please consider an upgrade"
    #EndIf
}

Se compilará en el siguiente código INT en Caché versión 2016.2.0.736:

zTest5() public {
   Write "You are using the latest released version of Caché"
}

Y lo siguiente se mostrará en la terminal:

You are using the latest released version of Caché

Si usamos Caché descargado del portal beta, el código INT compilado tendrá un aspecto diferente:

zTest5() public {
    Write "You are using the latest beta version of Caché"
}

Lo siguiente se mostrará en la terminal:

You are using the latest beta version of Caché

Las versiones anteriores de Caché compilarán el siguiente código INT con una sugerencia para actualizar el programa:

zTest5() public {
    Write "Please consider an upgrade"
}

El terminal mostrará el siguiente texto:

Please consider an upgrade

Esta capacidad puede ser útil, por ejemplo, en situaciones en las que desea garantizar la compatibilidad de la aplicación cliente con versiones anteriores y nuevas, donde se pueden utilizar las nuevas características de Caché. Directivas del pre procesador #IfDef, #IfNDef tienen el mismo propósito al verificar la existencia o ausencia de una macro, respectivamente.

Conclusiones

Las macros pueden hacer que su código sea más legible al simplificar las construcciones de uso frecuente y ayudarlo a implementar parte de la lógica de negocios de su aplicación en la etapa de compilación, reduciendo así la carga en tiempo de ejecución.

Enlaces

0
0 340
Artículo Kurro Lopez · jul 17, 2019 12m read


Las clases de consulta en InterSystems Caché son una herramienta muy útil que separa las consultas SQL del código Object Script de Caché. Básicamente funciona de la siguiente manera: supongamos que quiere utilizar la misma consulta SQL con distintos argumentos en varios lugares diferentes. En este caso, puede evitar la duplicación del código si declara el contenido de la consulta como una clase de consulta y después llama a esta consulta por su nombre. Este método también es conveniente para las consultas personalizadas, donde el desarrollador define con cuál de las tareas obtendrá la siguiente fila. ¿Esto le parece interesante? Entones, ¡siga leyendo!

0
0 793