Skip to content

Commit f973e4e

Browse files
committed
* Added start procedures
* Added lint flags for lint checks * Some minor code cleanup and rearranging * More comments
1 parent 7b39966 commit f973e4e

File tree

10 files changed

+391
-149
lines changed

10 files changed

+391
-149
lines changed

Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ endif
2929

3030
REGRESS = init-extension function json jsonb json_conv types bytea context \
3131
cursor array_spread plv8_regressions memory_limits inline composites \
32-
trigger procedure find_function
32+
trigger procedure find_function start_proc
3333

3434
all: deps/quickjs/quickjs.h deps/quickjs/libquickjs.a pljs--$(PLJS_VERSION).sql
3535

@@ -52,7 +52,7 @@ pljs--$(PLJS_VERSION).sql: pljs.sql
5252
$(CP) pljs.sql pljs--$(PLJS_VERSION).sql
5353

5454
lintcheck:
55-
clang-tidy $(SRCS) -- -I$(INCLUDEDIR) -I$(INCLUDEDIR_SERVER) -I$(PWD) --std=c11
55+
clang-tidy $(SRCS) -- $(LINTFLAGS) -I$(INCLUDEDIR) -I$(INCLUDEDIR_SERVER) -I$(PWD) --std=c11
5656

5757
all: deps/quickjs/quickjs.h deps/quickjs/libquickjs.a pljs--$(PLJS_VERSION).sql
5858

README.md

-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ It compiles, and is on track to match functionality of [PLV8](https://github.com
1919
Missing:
2020

2121
- Windows
22-
- SRF
23-
- startup functions
2422

2523
Also, WASM will likely never be added to this extension.
2624

ROADMAP.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Current Release Version: `0.8`
2828
- [x] caching of contexts and functions
2929
- [x] set returning functions
3030
- [ ] windows
31-
- [ ] startup functions
31+
- [x] startup functions
3232
- [x] procedures/transactions
3333
- [x] find function
3434
- [x] `BigInt`

expected/start_proc.out

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
CREATE FUNCTION start() RETURNS void AS
2+
$$
3+
pljs.elog(NOTICE, 'start function executed');
4+
pljs.current_scope = {
5+
"name": "current_scope"
6+
};
7+
$$ LANGUAGE pljs;
8+
SET pljs.start_proc = 'start';
9+
DO $$ pljs.elog(NOTICE, pljs.current_scope.name); $$ language pljs;
10+
NOTICE: searching for function
11+
NOTICE: start function executed
12+
NOTICE: current_scope
13+
-- setting a start proc after the context is created should change do anything
14+
SET pljs.start_proc = 'end';
15+
DO $$ pljs.elog(NOTICE, pljs.current_scope.name); $$ language pljs;
16+
NOTICE: current_scope
17+
-- a missing start proc should cause an error
18+
-- force the creation of a new context
19+
CREATE ROLE new_context;
20+
SET ROLE new_context;
21+
SET pljs.start_proc = 'end';
22+
DO $$ pljs.elog(NOTICE, pljs.current_scope.name); $$ language pljs;
23+
WARNING: failed to find pljs function function "end" does not exist:
24+
ERROR: execution error
25+
DETAIL: TypeError: cannot read property 'name' of undefined
26+
at <anonymous> (<function>:2)
27+
at <eval> (<function>:3)
28+
29+
RESET ROLE;
30+
DROP ROLE new_context;
31+
-- reset the start_proc
32+
SET pljs.start_proc = '';
33+
DROP FUNCTION start;
34+
-- test startup permissions failure
35+
CREATE FUNCTION start() RETURNS void AS $$ pljs.elog(NOTICE, 'nope'); $$ LANGUAGE pljs;
36+
CREATE ROLE someone_else;
37+
REVOKE EXECUTE ON FUNCTION start() FROM public;
38+
SET pljs.start_proc = 'start';
39+
REVOKE EXECUTE ON FUNCTION start() FROM public;
40+
SET ROLE TO someone_else;
41+
DO $$ pljs.elog(NOTICE, 'hello') $$ LANGUAGE pljs;
42+
WARNING: failed to find or no permission for js function start
43+
NOTICE: hello
44+
RESET ROLE;
45+
DROP ROLE someone_else;
46+
RESET pljs.start_proc;
47+
DROP FUNCTION start;

sql/start_proc.sql

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
CREATE FUNCTION start() RETURNS void AS
2+
$$
3+
pljs.elog(NOTICE, 'start function executed');
4+
pljs.current_scope = {
5+
"name": "current_scope"
6+
};
7+
$$ LANGUAGE pljs;
8+
9+
SET pljs.start_proc = 'start';
10+
11+
DO $$ pljs.elog(NOTICE, pljs.current_scope.name); $$ language pljs;
12+
13+
-- setting a start proc after the context is created should change do anything
14+
SET pljs.start_proc = 'end';
15+
16+
DO $$ pljs.elog(NOTICE, pljs.current_scope.name); $$ language pljs;
17+
18+
-- a missing start proc should cause an error
19+
-- force the creation of a new context
20+
CREATE ROLE new_context;
21+
SET ROLE new_context;
22+
23+
SET pljs.start_proc = 'end';
24+
DO $$ pljs.elog(NOTICE, pljs.current_scope.name); $$ language pljs;
25+
26+
RESET ROLE;
27+
DROP ROLE new_context;
28+
29+
-- reset the start_proc
30+
SET pljs.start_proc = '';
31+
32+
DROP FUNCTION start;
33+
34+
-- test startup permissions failure
35+
CREATE FUNCTION start() RETURNS void AS $$ pljs.elog(NOTICE, 'nope'); $$ LANGUAGE pljs;
36+
37+
CREATE ROLE someone_else;
38+
39+
REVOKE EXECUTE ON FUNCTION start() FROM public;
40+
41+
SET pljs.start_proc = 'start';
42+
REVOKE EXECUTE ON FUNCTION start() FROM public;
43+
44+
SET ROLE TO someone_else;
45+
DO $$ pljs.elog(NOTICE, 'hello') $$ LANGUAGE pljs;
46+
47+
RESET ROLE;
48+
DROP ROLE someone_else;
49+
50+
RESET pljs.start_proc;
51+
52+
DROP FUNCTION start;

src/cache.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ void pljs_cache_reset(void) {
6363
* Creates a #pljs_context_cache_value and fills it with the
6464
* javascript context and #HTAB storing #pljs_function_cache_value
6565
* entries by `fn_oid`.
66+
*
67+
* @param user_id #Oid - user ID for the #JSContext to be assigned to
68+
* @param ctx #JSContext - context to be added to the cache
6669
*/
6770
void pljs_cache_context_add(Oid user_id, JSContext *ctx) {
6871
bool found;
@@ -107,7 +110,7 @@ void pljs_cache_context_add(Oid user_id, JSContext *ctx) {
107110
* @brief Removes a #pljs_context_cache_value for a `user_id`.
108111
*
109112
* Removes a cache entry from the cache by `user_id`.
110-
* @param user_id #Oid
113+
* @param user_id #Oid - user ID for which to remove the cache entries
111114
*/
112115
void pljs_cache_context_remove(Oid user_id) {
113116
bool found;
@@ -125,7 +128,7 @@ void pljs_cache_context_remove(Oid user_id) {
125128
* @brief Finds a #pljs_context_cache_value for a `user_id`.
126129
*
127130
* @param user_id #Oid
128-
* @returns #pljs_context_cache_value that is found, or `NULL` if not found.
131+
* @returns #pljs_context_cache_value that is found, or `NULL` if not found
129132
*/
130133
pljs_context_cache_value *pljs_cache_context_find(Oid user_id) {
131134
pljs_context_cache_value *value = (pljs_context_cache_value *)hash_search(
@@ -186,7 +189,7 @@ void pljs_cache_function_add(pljs_context *context) {
186189
*
187190
* @param user_id #Oid
188191
* @param fn_oid #Oid
189-
* @returns #pljs_function_cache_value that is found, or `NULL` if not found.
192+
* @returns #pljs_function_cache_value that is found, or `NULL` if not found
190193
*/
191194
pljs_function_cache_value *pljs_cache_function_find(Oid user_id, Oid fn_oid) {
192195
bool found;

src/functions.c

+13-45
Original file line numberDiff line numberDiff line change
@@ -743,52 +743,25 @@ static JSValue pljs_find_function(JSContext *ctx, JSValueConst this_val,
743743
const char *signature = JS_ToCString(ctx, argv[0]);
744744
JSValue func = JS_UNDEFINED;
745745

746-
// Stack-allocate FunctionCallInfoBaseData with
747-
// space for 2 arguments:
748-
LOCAL_FCINFO(fake_fcinfo, 2);
749-
750-
FmgrInfo flinfo;
751-
752-
char perm[16];
753-
strcpy(perm, "EXECUTE");
754-
text *arg = (text *)palloc(8 + VARHDRSZ);
755-
memcpy(VARDATA(arg), perm, 8);
756-
SET_VARSIZE(arg, 8 + VARHDRSZ);
757-
Oid funcoid;
758-
759746
PG_TRY();
760747
{
761-
if (strchr(signature, '(') == NULL) {
762-
funcoid = DatumGetObjectId(
763-
DirectFunctionCall1(regprocin, CStringGetDatum(signature)));
764-
} else {
765-
funcoid = DatumGetObjectId(
766-
DirectFunctionCall1(regprocedurein, CStringGetDatum(signature)));
767-
}
768-
769-
MemSet(&flinfo, 0, sizeof(flinfo));
770-
fake_fcinfo->flinfo = &flinfo;
771-
flinfo.fn_oid = InvalidOid;
772-
flinfo.fn_mcxt = CurrentMemoryContext;
773-
fake_fcinfo->nargs = 2;
774-
fake_fcinfo->args[0].value = ObjectIdGetDatum(funcoid);
775-
fake_fcinfo->args[1].value = PointerGetDatum(arg);
748+
Oid funcoid;
776749

777-
Datum ret = has_function_privilege_id(fake_fcinfo);
778-
779-
if (ret == 0) {
780-
elog(WARNING, "failed to find or no permission for js function %s",
781-
signature);
750+
if (!has_permission_to_execute(signature)) {
782751
return func;
783752
} else {
784-
if (DatumGetBool(ret)) {
785-
func = pljs_find_js_function(funcoid);
786-
787-
if (JS_IsUndefined(func)) {
788-
elog(ERROR, "javascript function is not found for \"%s\"", signature);
789-
}
753+
if (strchr(signature, '(') == NULL) {
754+
funcoid = DatumGetObjectId(
755+
DirectFunctionCall1(regprocin, CStringGetDatum(signature)));
790756
} else {
791-
elog(WARNING, "no permission to execute js function %s", signature);
757+
funcoid = DatumGetObjectId(
758+
DirectFunctionCall1(regprocedurein, CStringGetDatum(signature)));
759+
}
760+
761+
func = pljs_find_js_function(funcoid, ctx);
762+
763+
if (JS_IsUndefined(func)) {
764+
elog(ERROR, "javascript function is not found for \"%s\"", signature);
792765
}
793766
}
794767
}
@@ -808,11 +781,6 @@ static JSValue pljs_find_function(JSContext *ctx, JSValueConst this_val,
808781

809782
static JSValue pljs_return_next(JSContext *ctx, JSValueConst this_val, int argc,
810783
JSValueConst *argv) {
811-
const char *sql;
812-
JSValue params = {0};
813-
int nparams;
814-
Oid *types = NULL;
815-
SPIPlanPtr initial = NULL, saved = NULL;
816784
pljs_return_state *retstate = NULL;
817785

818786
JSValue global_obj = JS_GetGlobalObject(ctx);

0 commit comments

Comments
 (0)