@@ -35,15 +35,21 @@ PG_MODULE_MAGIC;
3535
3636PG_FUNCTION_INFO_V1 (plv8_call_handler);
3737PG_FUNCTION_INFO_V1 (plv8_call_validator);
38+ PG_FUNCTION_INFO_V1 (plcoffee_call_handler);
39+ PG_FUNCTION_INFO_V1 (plcoffee_call_validator);
3840
3941Datum plv8_call_handler (PG_FUNCTION_ARGS) throw();
4042Datum plv8_call_validator (PG_FUNCTION_ARGS) throw();
43+ Datum plcoffee_call_handler (PG_FUNCTION_ARGS) throw();
44+ Datum plcoffee_call_validator (PG_FUNCTION_ARGS) throw();
4145
4246void _PG_init (void );
4347
4448#if PG_VERSION_NUM >= 90000
4549PG_FUNCTION_INFO_V1 (plv8_inline_handler);
50+ PG_FUNCTION_INFO_V1 (plcoffee_inline_handler);
4651Datum plv8_inline_handler (PG_FUNCTION_ARGS) throw();
52+ Datum plcoffee_inline_handler (PG_FUNCTION_ARGS) throw();
4753#endif
4854} // extern "C"
4955
@@ -106,6 +112,8 @@ static HTAB *plv8_proc_cache_hash = NULL;
106112
107113static plv8_exec_env *exec_env_head = NULL ;
108114
115+ extern const unsigned char coffee_script_binary_data[];
116+
109117/*
110118 * lower_case_functions are postgres-like C functions.
111119 * They could raise errors with elog/ereport(ERROR).
@@ -118,10 +126,11 @@ static void plv8_xact_cb(XactEvent event, void *arg);
118126 * They could raise errors with C++ throw statements, or never throw exceptions.
119127 */
120128static plv8_exec_env *CreateExecEnv (Handle<Function> script);
121- static plv8_proc *Compile (Oid fn_oid, MemoryContext fn_mcxt, bool validate, bool is_trigger);
129+ static plv8_proc *Compile (Oid fn_oid, MemoryContext fn_mcxt,
130+ bool validate, bool is_trigger, bool is_coffee);
122131static Local<Function> CompileFunction (const char *proname, int proarglen,
123132 const char *proargs[], const char *prosrc,
124- bool is_trigger, bool retset);
133+ bool is_trigger, bool retset, bool is_coffee );
125134static Datum CallFunction (PG_FUNCTION_ARGS, plv8_exec_env *xenv,
126135 int nargs, plv8_type argtypes[], plv8_type *rettype);
127136static Datum CallSRFunction (PG_FUNCTION_ARGS, plv8_exec_env *xenv,
@@ -205,8 +214,8 @@ plv8_new_exec_env()
205214 return xenv;
206215}
207216
208- Datum
209- plv8_call_handler (PG_FUNCTION_ARGS) throw()
217+ static Datum
218+ common_pl_call_handler (PG_FUNCTION_ARGS, bool is_coffee ) throw()
210219{
211220 Oid fn_oid = fcinfo->flinfo ->fn_oid ;
212221 bool is_trigger = CALLED_AS_TRIGGER (fcinfo);
@@ -218,7 +227,7 @@ plv8_call_handler(PG_FUNCTION_ARGS) throw()
218227 if (!fcinfo->flinfo ->fn_extra )
219228 {
220229 plv8_proc *proc = Compile (fn_oid, fcinfo->flinfo ->fn_mcxt ,
221- false , is_trigger);
230+ false , is_trigger, is_coffee );
222231 proc->xenv = CreateExecEnv (proc->cache ->function );
223232 fcinfo->flinfo ->fn_extra = proc;
224233 }
@@ -241,9 +250,21 @@ plv8_call_handler(PG_FUNCTION_ARGS) throw()
241250 return (Datum) 0 ; // keep compiler quiet
242251}
243252
244- #if PG_VERSION_NUM >= 90000
245253Datum
246- plv8_inline_handler (PG_FUNCTION_ARGS) throw()
254+ plv8_call_handler (PG_FUNCTION_ARGS) throw()
255+ {
256+ return common_pl_call_handler (fcinfo, false );
257+ }
258+
259+ Datum
260+ plcoffee_call_handler (PG_FUNCTION_ARGS) throw()
261+ {
262+ return common_pl_call_handler (fcinfo, true );
263+ }
264+
265+ #if PG_VERSION_NUM >= 90000
266+ static Datum
267+ common_pl_inline_handler (PG_FUNCTION_ARGS, bool is_coffee) throw()
247268{
248269 InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer (PG_GETARG_DATUM (0 ));
249270
@@ -252,9 +273,10 @@ plv8_inline_handler(PG_FUNCTION_ARGS) throw()
252273 try
253274 {
254275 HandleScope handle_scope;
276+ char *source_text = codeblock->source_text ;
255277
256278 Handle<Function> function = CompileFunction (NULL , 0 , NULL ,
257- codeblock-> source_text , false , false );
279+ source_text, false , false , is_coffee );
258280 plv8_exec_env *xenv = CreateExecEnv (function);
259281 return CallFunction (fcinfo, xenv, 0 , NULL , NULL );
260282 }
@@ -263,6 +285,18 @@ plv8_inline_handler(PG_FUNCTION_ARGS) throw()
263285
264286 return (Datum) 0 ; // keep compiler quiet
265287}
288+
289+ Datum
290+ plv8_inline_handler (PG_FUNCTION_ARGS) throw()
291+ {
292+ return common_pl_inline_handler (fcinfo, false );
293+ }
294+
295+ Datum
296+ plcoffee_inline_handler (PG_FUNCTION_ARGS) throw()
297+ {
298+ return common_pl_inline_handler (fcinfo, true );
299+ }
266300#endif
267301
268302/*
@@ -558,8 +592,8 @@ CallTrigger(PG_FUNCTION_ARGS, plv8_exec_env *xenv)
558592 return result;
559593}
560594
561- Datum
562- plv8_call_validator (PG_FUNCTION_ARGS) throw()
595+ static Datum
596+ common_pl_call_validator (PG_FUNCTION_ARGS, bool is_coffee ) throw()
563597{
564598 Oid fn_oid = PG_GETARG_OID (0 );
565599 HeapTuple tuple;
@@ -596,7 +630,7 @@ plv8_call_validator(PG_FUNCTION_ARGS) throw()
596630 try
597631 {
598632 plv8_proc *proc = Compile (fn_oid, fcinfo->flinfo ->fn_mcxt ,
599- true , is_trigger);
633+ true , is_trigger, is_coffee );
600634 (void ) CreateExecEnv (proc->cache ->function );
601635 /* the result of a validator is ignored */
602636 PG_RETURN_VOID ();
@@ -607,6 +641,18 @@ plv8_call_validator(PG_FUNCTION_ARGS) throw()
607641 return (Datum) 0 ; // keep compiler quiet
608642}
609643
644+ Datum
645+ plv8_call_validator (PG_FUNCTION_ARGS) throw()
646+ {
647+ return common_pl_call_validator (fcinfo, false );
648+ }
649+
650+ Datum
651+ plcoffee_call_validator (PG_FUNCTION_ARGS) throw()
652+ {
653+ return common_pl_call_validator (fcinfo, true );
654+ }
655+
610656static plv8_proc *
611657plv8_get_proc (Oid fn_oid, MemoryContext fn_mcxt, bool validate, char ***argnames) throw()
612658{
@@ -769,8 +815,64 @@ CreateExecEnv(Handle<Function> function)
769815 return xenv;
770816}
771817
818+ /* Source transformation from coffee to js */
819+ static char *
820+ CompileCoffee (const char *src)
821+ {
822+ HandleScope handle_scope;
823+ static Persistent<Context> context = Context::New (NULL );
824+ Context::Scope context_scope (context);
825+ TryCatch try_catch;
826+ Local<String> key = String::NewSymbol (" CoffeeScript" );
827+ char *cresult;
828+
829+ #ifndef ENABLE_COFFEE
830+ throw js_error (" coffee script is not enabled" );
831+ #endif
832+
833+ if (context->Global ()->Get (key)->IsUndefined ())
834+ {
835+ HandleScope handle_scope;
836+ Local<Script> script =
837+ Script::New (ToString ((const char *) coffee_script_binary_data),
838+ ToString (" coffee" ));
839+ if (script.IsEmpty ())
840+ throw js_error (try_catch);
841+ Local<v8::Value> result = script->Run ();
842+ if (result.IsEmpty ())
843+ throw js_error (try_catch);
844+ }
845+
846+ Local<Object> compiler = Local<Object>::Cast (context->Global ()->Get (key));
847+ Local<Function> func = Local<Function>::Cast (
848+ compiler->Get (String::NewSymbol (" compile" )));
849+ int nargs = 1 ;
850+ Handle<v8::Value> args[nargs];
851+
852+ args[0 ] = ToString (src);
853+ Local<v8::Value> value = func->Call (compiler, nargs, args);
854+
855+ if (value.IsEmpty ())
856+ throw js_error (try_catch);
857+ CString result (value);
858+
859+ PG_TRY ();
860+ {
861+ MemoryContext oldcontext = MemoryContextSwitchTo (TopMemoryContext);
862+ cresult = pstrdup (result.str ());
863+ MemoryContextSwitchTo (oldcontext);
864+ }
865+ PG_CATCH ();
866+ {
867+ throw pg_error ();
868+ }
869+ PG_END_TRY ();
870+
871+ return cresult;
872+ }
873+
772874static plv8_proc *
773- Compile (Oid fn_oid, MemoryContext fn_mcxt, bool validate, bool is_trigger)
875+ Compile (Oid fn_oid, MemoryContext fn_mcxt, bool validate, bool is_trigger, bool is_coffee )
774876{
775877 plv8_proc *proc;
776878 char **argnames;
@@ -795,7 +897,8 @@ Compile(Oid fn_oid, MemoryContext fn_mcxt, bool validate, bool is_trigger)
795897 (const char **) argnames,
796898 cache->prosrc ,
797899 is_trigger,
798- cache->retset ));
900+ cache->retset ,
901+ is_coffee));
799902
800903 return proc;
801904}
@@ -807,14 +910,17 @@ CompileFunction(
807910 const char *proargs[],
808911 const char *prosrc,
809912 bool is_trigger,
810- bool retset)
913+ bool retset,
914+ bool is_coffee)
811915{
812916 HandleScope handle_scope;
813917 StringInfoData src;
814918 Handle<Context> global_context = GetGlobalContext ();
815919
816920 initStringInfo (&src);
817921
922+ if (is_coffee)
923+ prosrc = CompileCoffee (prosrc);
818924 /*
819925 * (function (<arg1, ...>){
820926 * <prosrc>
@@ -842,7 +948,10 @@ CompileFunction(
842948 appendStringInfo (&src, " $%d" , i + 1 ); // unnamed argument to $N
843949 }
844950 }
845- appendStringInfo (&src, " ){\n %s\n })" , prosrc);
951+ if (is_coffee)
952+ appendStringInfo (&src, " ){\n return %s\n })" , prosrc);
953+ else
954+ appendStringInfo (&src, " ){\n %s\n })" , prosrc);
846955
847956 Handle<v8::Value> name;
848957 if (proname)
@@ -871,8 +980,9 @@ find_js_function(Oid fn_oid)
871980{
872981 HeapTuple tuple;
873982 Form_pg_proc proc;
874- Oid prolang, langtupoid;
875- NameData langname = { " plv8" };
983+ Oid prolang, v8langtupoid, coffeelangtupoid;
984+ NameData v8langname = { " plv8" },
985+ coffeelangname = { " plcoffee" };
876986
877987 tuple = SearchSysCache (PROCOID, ObjectIdGetDatum (fn_oid), 0 , 0 , 0 );
878988 if (!HeapTupleIsValid (tuple))
@@ -881,21 +991,35 @@ find_js_function(Oid fn_oid)
881991 prolang = proc->prolang ;
882992 ReleaseSysCache (tuple);
883993
884- tuple = SearchSysCache (LANGNAME, NameGetDatum (&langname ), 0 , 0 , 0 );
994+ tuple = SearchSysCache (LANGNAME, NameGetDatum (&v8langname ), 0 , 0 , 0 );
885995 if (!HeapTupleIsValid (tuple))
886- elog (ERROR, " cache look up failed for language %s" , NameStr (langname));
887- langtupoid = HeapTupleGetOid (tuple);
888- ReleaseSysCache (tuple);
996+ v8langtupoid = InvalidOid;
997+ else
998+ {
999+ v8langtupoid = HeapTupleGetOid (tuple);
1000+ ReleaseSysCache (tuple);
1001+ }
1002+
1003+ tuple = SearchSysCache (LANGNAME, NameGetDatum (&coffeelangname), 0 , 0 , 0 );
1004+ if (!HeapTupleIsValid (tuple))
1005+ coffeelangtupoid = InvalidOid;
1006+ else
1007+ {
1008+ coffeelangtupoid = HeapTupleGetOid (tuple);
1009+ ReleaseSysCache (tuple);
1010+ }
8891011
8901012 Local<Function> func;
8911013
8921014 /* Non-JS function */
893- if (langtupoid != prolang)
1015+ if (prolang == InvalidOid ||
1016+ (v8langtupoid != prolang && coffeelangtupoid != prolang))
8941017 return func;
8951018
8961019 try
8971020 {
898- plv8_proc *proc = Compile (fn_oid, CurrentMemoryContext, true , false );
1021+ plv8_proc *proc = Compile (fn_oid,CurrentMemoryContext,
1022+ true , false , coffeelangtupoid == prolang);
8991023
9001024 TryCatch try_catch;
9011025
0 commit comments