1# PLV8 Built-ins 2 3PLV8 includes a number of built-in functions bound to the `plv8` object for you 4to use. 5 6## Utility Functions 7 8### `plv8.elog` 9 10`plv8.elog` emits a message to the client or the PostgreSQL log file. The 11emit level is one of: 12 13* `DEBUG5` 14* `DEBUG4` 15* `DEBUG3` 16* `DEBUG2` 17* `DEBUG1` 18* `LOG` 19* `INFO` 20* `NOTICE` 21* `WARNING` 22* `ERROR` 23 24``` 25var msg = 'world'; 26 27plv8.elog(DEBUG1, 'Hello', `${msg}!`); 28``` 29 30See the [PostgreSQL manual](https://www.postgresql.org/docs/current/static/runtime-config-logging.html#RUNTIME-CONFIG-SEVERITY-LEVELS) for information on each error level. 31 32### `plv8.quote_literal`, `plv8.nullable`, `plv8.quote_ident` 33 34Each function for the quote family is identical to the built-in SQL function 35with the same name. 36 37### `plv8.find_function` 38 39PLV8 provides a function to access other functions defined as `plv8` functions 40that have been registered in the database. 41 42``` 43CREATE FUNCTION callee(a int) RETURNS int AS $$ return a * a $$ LANGUAGE plv8; 44CREATE FUNCTION caller(a int, t int) RETURNS int AS $$ 45 var func = plv8.find_function("callee"); 46 return func(a); 47$$ LANGUAGE plv8; 48``` 49 50With `plv8.find_function()``, you can look up other PLV8 functions. If they 51are not a PLV8 function, and error is thrown. The function signature parameter 52to `plv8.find_function()`` is either of `regproc` (function name only) or 53`regprocedure` (function name with argument types). You can make use of the 54internal type for arguments and void type for return type for the pure Javascript 55function to make sure any invocation from SQL statements should not occur. 56 57### `plv8.version` 58 59The `plv8` object provides a version string as `plv8.version`. This string 60corresponds to the `plv8` module version. 61 62## Database Access via SPI 63 64PLV8 provides functions for database access, including prepared statements, 65and cursors. 66 67### `plv8.execute` 68 69`plv8.execute(sql [, args])` 70 71Executes SQL statements and retrieves the results. The `sql` argument is 72required, and the `args` argument is an optional `array` containing any arguments 73passed in the SQL query. For `SELECT` queries, the returned value is an `array` 74of `objects`. Each `object` represents one row, with the `object` properties 75mapped as column names. For non-`SELECT` queries, the return result is the 76number of rows affected. 77 78``` 79var json_result = plv8.execute('SELECT * FROM tbl'); 80var num_affected = plv8.execute('DELETE FROM tbl WHERE price > $1', [ 1000 ]); 81``` 82 83### `plv8.prepare` 84 85`plv8.prepare(sql [, typenames])` 86 87Opens or creates a prepared statement. The `typename` parameter is an `array` 88where each element is a `string` that corresponds to the PostgreSQL type name 89for each `bind` parameter. Returned value is an object of the `PreparedPlan` type. 90This object must be freed by `plan.free()` before leaving the function. 91 92``` 93var plan = plv8.prepare('SELECT * FROM tbl WHERE col = $1', [ 'int' ]); 94var rows = plan.execute([ 1 ]); 95var sum = 0; 96for (var i = 0; i < rows.length; i++) { 97 sum += rows[i].num; 98} 99plan.free(); 100 101return sum; 102``` 103 104### `PreparedPlan.execute` 105 106`PreparedPlan.execute([ args ])` 107 108Executes the prepared statement. The `args` parameter is the same as what would be 109required for `plv8.execute()`, and can be omitted if the statement does not have 110any parameters. The result of this method is also the same as `plv8.execute()`. 111 112### `PreparedPlan.cursor` 113 114`PreparedPlan.cursor([ args ])` 115 116Opens a cursor form the prepared statement. The `args` parameter is the same as 117what would be required for `plv8.execute()` and `PreparedPlan.execute()`. The 118returned object is of type `Cursor`. This must be closed by `Cursor.close()` 119before leaving the function. 120 121``` 122var plan = plv8.prepare('SELECT * FROM tbl WHERE col = $1', [ 'int' ]); 123var cursor = plan.cursor([ 1 ]); 124var sum = 0, row; 125while (row = cursor.fetch()) { 126 sum += row.num; 127} 128cursor.close(); 129plan.free(); 130 131return sum; 132``` 133 134### `PreparedPlan.free` 135 136Frees the prepared statement. 137 138### `Cursor.fetch` 139 140`Cursor.fetch([ nrows ])` 141 142When the `nrows` parameter is omitted, fetches a row from the cursor and returns 143it as an `object` (note: not as an `array`). If specified, fetches as many rows 144as the `nrows` parameter, up to the number of rows available, and returns an 145`array` of `objects`. A negative value will fetch backward. 146 147### `Cursor.move` 148 149`Cursor.move(nrows)` 150 151Moves the cursor `nrows`. A negative value will move backward. 152 153### `Cursor.close` 154 155Closes the `Cursor`. 156 157### `plv8.subtransaction` 158 159`plv8.subtransaction(func)` 160 161`plv8.execute()` creates a subtransaction each time it executes. If you need 162an atomic operation, you will need to call `plv8.subtransaction()` to create 163a subtransaction block. 164 165``` 166try{ 167 plv8.subtransaction(function(){ 168 plv8.execute("INSERT INTO tbl VALUES(1)"); // should be rolled back! 169 plv8.execute("INSERT INTO tbl VALUES(1/0)"); // occurs an exception 170 }); 171} catch(e) { 172 ... execute fall back plan ... 173} 174``` 175 176If one of the SQL execution in the subtransaction block fails, all of operations 177within the block are rolled back. If the process in the block throws a Javascript 178exception, it is carried forward. So use a `try ... catch` block to capture it and 179do alternative operations if it occurs. 180 181## Window Function API 182 183You can define user-defined window functions with PLV8. It wraps the C-level 184window function API to support full functionality. To create one, first obtain a 185window object by calling `plv8.get_window_object()`, which provides the following 186interfaces: 187 188### `WindowObject.get_current_position` 189 190Returns the current position in the partition, starting from `0`. 191 192### `WindowObject.get_partition_row_count` 193 194Returns the number of rows in the partition. 195 196### `WindowObject.set_mark_position` 197 198`WindowObject.set_mark_position(pos)` 199 200Sets the mark at the specified row. Rows above this position will be gone and 201no longer accessible later. 202 203### `WindowObject.rows_are_peers` 204 205`WindowObject.rows_are_peers(pos1, pos1)` 206 207Returns `true` if the rows at `pos1` and `pos2` are peers. 208 209### `WindowObject.get_func_arg_in_partition` 210 211`WindowObject.get_func_arg_in_partition(argno, relpos, seektype, mark_pos)` 212 213### `WindowObject.get_func_arg_in_frame` 214 215`WindowObject.get_func_arg_in_frame(argno, relpos, seektype, mark_pos)` 216 217Returns the value of the argument in `argno` (starting from 0) to this function 218at the `relpos` row from `seektype` in the current partition or frame. 219`seektype` can be either of `WindowObject.SEEK_HEAD`, `WindowObject.SEEK_CURRENT`, 220or `WindowObject.SEEK_TAIL`. If `mark_pos` is `true`, the row the argument is 221fetched from is marked. If the specified row is out of the partition/frame, the 222returned value will be undefined. 223 224 225### `WindowObject.get_func_arg_in_current` 226 227`WindowObject.get_func_arg_in_current(argno)` 228 229Returns the value of the argument in `argno` (starting from 0) to this function 230at the current row. Note that the returned value will be the same as the argument 231variable of the function. 232 233### `WindowObject.get_partition_local` 234 235`WindowObject.get_partition_local([ size ])` 236 237Returns partition-local value, which is released at the end of the current 238partition. If nothing is stored, undefined is returned. size argument (default 2391000) is the byte size of the allocated memory in the first call. Once the memory 240is allocated, the size will not change. 241 242### `WindowObject.set_partition_local` 243 244`WindowObject.set_partition_local(obj)` 245 246Stores the partition-local value, which you can retrieve later with 247`get_partition_local()``. This function internally uses `JSON.stringify()` to\ 248serialize the object, so if you pass a value that is not able to be serialized 249it may end up being an unexpected value. If the size of a serialized value is 250more than the allocated memory, it will throw an exception. 251 252You can also learn more on how to use these API in the `sql/window.sql` 253regression test, which implements most of the native window functions. For 254general information on the user-defined window function, see the [CREATE FUNCTION page of the PostgreSQL manual](https://www.postgresql.org/docs/current/static/sql-createfunction.html). 255