En blogs anteriores, cubrimos la ejecución de N1QL (SQL++) desde JavaScript funcionesTramitación de documentos a través de iteradores, manipular datos, gestión de erroresy utilizando declaraciones preparadas. Tenemos que cubrir algunos temas más avanzados antes de pasar a la manipulación de bibliotecas JavaScript, como la llamada a otras funciones, el uso de transacciones y RBAC.
Funciones de llamada
Las funciones JavaScript pueden llamar directamente a otras funciones JavaScript.
Cualquier sentencia N1QL ejecutada en la función llamada será ejecutada de la misma manera, y con exactamente las mismas limitaciones, como si fuera ejecutada en la función llamada. Los resultados pueden viajar libremente arriba y abajo de la pila y cualquier excepción lanzada en la función llamada hará su camino hacia abajo de la pila a la petición N1QL de llamada (a menos que sea capturada y manejada en algún lugar).
Esta es definitivamente una forma más práctica de llamar a funciones que ejecutar sentencias N1QL que llaman a UDFs N1QL. Al llamar a las funciones directamente en lugar de pasar por EJECUTAR FUNCIÓN se evita completamente la capa N1QL y se ahorran todos los recursos necesarios para cambiar de JavaScript a N1QL y de nuevo a JavaScript. Esto reduce el coste de los cambios de contexto, tener que mover todos los datos a través de iteradores y no directamente, y tener que dejar iteradores abiertos durante la duración de la llamada.
Ejecución de N1QL que llama a funciones
Hay veces en las que usted ejecutará sentencias N1QL que llaman a UDFs N1QL y estas UDFs pueden muy bien ser funciones JavaScript en sí mismas.
Esto es absolutamente de esperar, y funciona exactamente de la misma manera que todo lo que hemos descrito hasta ahora.
La única limitación que debe tener en cuenta es que mientras cualquier sentencia N1QL que JavaScript pueda ejecutar se ejecutará en el mismo servidor que está ejecutando la petición principal. Cada llamada a una función JavaScript utilizará un nuevo trabajador JavaScript, lo que significa que cuantas más llamadas UDF N1QL anidadas realice, menos trabajadores estarán disponibles, y la función acabará fallando de esta forma:
1 2 3 |
función doRecursion() { var q = ejecutar función doRecursion(); } |
1 |
CREAR FUNCIÓN doRecursion() IDIOMA JAVASCRIPT AS "doRecursion" EN "udfblog" |
Que rinde:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
[ { "código": 10109, "msg": "Error al ejecutar la función 'doRecursion' (udfblog:doRecursion)", "razón": { "detalles": { "Código": "var q = N1QL('ejecutar función doRecursion();', {}, true);", "Excepción": { "llamante": "javascript:133", "código": 10112, "llave": "function.nested.error", "mensaje": "Error al ejecutar la función 'doRecursion': 25 llamadas javascript anidadas" }, "Localización": "functions/udfblog.js:11", "Pila": " at doRecursion (functions/udfblog.js:11:13)" }, "tipo": "Excepciones del código JS" } } ] |
El límite de anidamiento no es fijo, y depende del número de trabajadores JavaScript disponibles en el momento en que se ejecuta cada llamada anidada; en términos generales, cuanto mayor sea la actividad JavaScript presente en el nodo, menor será este límite.
En el ejemplo anterior, el nodo tenía 48 trabajadores y falló en la 25ª llamada.
RBAC
Para ejecutar N1QL como parte de funciones JavaScript, el usuario que ejecuta la función necesita tener los privilegios apropiados para realizar las acciones (insertar, seleccione...) especificados en la función sobre los objetos referenciados por la función.
Dado que la identidad del usuario que ejecuta la función no se conoce hasta el momento de la ejecución, cualquier error de privilegio sólo se producirá cuando se ejecute la función, suponiendo que el usuario que ejecuta la función tenga privilegios para ejecutar funciones JavaScript.
Esto coincide con lo que hacen otros motores de bases de datos.
Efectos secundarios
Las funciones que se ejecutan como parte de expresiones, no pueden tener efectos secundarios: lo que significa que no se permite ejecutar ningún DML como parte de esa función. Esto está en línea con lo que hacen otros motores de bases de datos y tiene sentido. No querrías una función SELECCIONE para insertar datos a sus espaldas mediante el uso de una función JavaScript.
La única forma de que las funciones manipulen el almacenamiento es ejecutarlas de forma aislada a través de la función EJECUTAR FUNCIÓN declaración.
Transacciones
Es perfectamente legal ejecutar sentencias N1QL transaccionales dentro de una función JavaScript, siempre que la función se ejecute con la capacidad de tener efectos secundarios, es decir, a través de la función EJECUTAR FUNCIÓN declaración. La función puede ejecutar DML en una transacción que se había iniciado antes de ejecutar la función, puede iniciar la transacción, puede consignar o revertir la transacción, o cualquier combinación legal de las mismas.
Lo único que hay que tener en cuenta es que las sentencias N1QL y los iteradores sólo viven completamente dentro o fuera de una transacción, pero no a medias. Esto significa que si se había iniciado una sentencia select antes de una transacción, pero no se habían consumido todos los valores, en cuanto se inicie la transacción, ese iterador se cerrará. Lo mismo ocurre con las sentencias DML que devuelven resultados (se completan antes de que la transacción pueda iniciarse), y se aplica un comportamiento similar cuando una transacción se consigna o se revierte.
Hay buenas razones para ello, y el comportamiento es generalmente coherente con lo que ocurre con los motores de bases de datos. El motivo es que si permitiéramos que las sentencias sobrevivieran a los límites de la transacción, las sentencias select no podrían acceder a los cambios de la transacción y las sentencias DML no podrían revertirse en su totalidad.
Para evitar dudas, no se puede iniciar una transacción dentro de un bucle que procesa un SELECCIONE ya que el iterador se cerrará en cuanto se inicie la transacción. Todo el exterior SELECCIONE debe estar dentro de la transacción.
Conclusión
Con este blog hemos cubierto los principales temas relacionados con la ejecución de N1QL dentro de funciones JavaScript. El próximo blog se centrará en las nuevas funciones de gestión de bibliotecas JavaScript.