1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/*
10 * Martin Kersten
11 * Language Extensions
12 * Iterators over scalar ranges are often needed, also at the MAL level.
13 * The barrier and control primitives are sufficient to mimic them directly.
14 *
15 * The modules located in the kernel directory should not
16 * rely on the MAL datastructures. That's why we have to deal with
17 * some bat operations here and delegate the signature to the
18 * proper module upon loading.
19 *
20 * Running a script is typically used to initialize a context.
21 * Therefore we need access to the runtime context.
22 * For the call variants we have
23 * to determine an easy way to exchange the parameter/return values.
24 */
25
26#include "monetdb_config.h"
27#include "language.h"
28
29str
30CMDraise(str *ret, str *msg)
31{
32 str res;
33 *ret = GDKstrdup(*msg);
34 if( *ret == NULL)
35 throw(MAL, "mal.raise", SQLSTATE(HY001) MAL_MALLOC_FAIL);
36 res = GDKstrdup(*msg);
37 if( res == NULL)
38 throw(MAL, "mal.raise", SQLSTATE(HY001) MAL_MALLOC_FAIL);
39 return res;
40}
41
42str
43MALassertBit(void *ret, bit *val, str *msg){
44 (void) ret;
45 if( *val == 0 || is_bit_nil(*val))
46 throw(MAL, "mal.assert", "%s", *msg);
47 return MAL_SUCCEED;
48}
49str
50MALassertInt(void *ret, int *val, str *msg){
51 (void) ret;
52 if( *val == 0 || is_int_nil(*val))
53 throw(MAL, "mal.assert", "%s", *msg);
54 return MAL_SUCCEED;
55}
56str
57MALassertLng(void *ret, lng *val, str *msg){
58 (void) ret;
59 if( *val == 0 || is_lng_nil(*val))
60 throw(MAL, "mal.assert", "%s", *msg);
61 return MAL_SUCCEED;
62}
63#ifdef HAVE_HGE
64str
65MALassertHge(void *ret, hge *val, str *msg){
66 (void) ret;
67 if( *val == 0 || is_hge_nil(*val))
68 throw(MAL, "mal.assert", "%s", *msg);
69 return MAL_SUCCEED;
70}
71#endif
72str
73MALassertSht(void *ret, sht *val, str *msg){
74 (void) ret;
75 if( *val == 0 || is_sht_nil(*val))
76 throw(MAL, "mal.assert", "%s", *msg);
77 return MAL_SUCCEED;
78}
79str
80MALassertOid(void *ret, oid *val, str *msg){
81 (void) ret;
82 if( is_oid_nil(*val))
83 throw(MAL, "mal.assert", "%s", *msg);
84 return MAL_SUCCEED;
85}
86str
87MALassertStr(void *ret, str *val, str *msg){
88 (void) ret;
89 if( *val == str_nil)
90 throw(MAL, "mal.assert", "%s", *msg);
91 return MAL_SUCCEED;
92}
93
94str
95MALassertTriple(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p){
96 (void) cntxt;
97 (void) mb;
98 (void) stk;
99 (void) p;
100 throw(MAL, "mal.assert", SQLSTATE(0A000) PROGRAM_NYI);
101}
102
103/*
104 * Printing
105 * The print commands are implemented as single instruction rules,
106 * because they need access to the calling context.
107 * At a later stage we can look into the issues related to
108 * parsing the format string as part of the initialization phase.
109 * The old method in V4 essentially causes a lot of overhead
110 * because you have to prepare for the worst (e.g. mismatch format
111 * identifier and argument value)
112 *
113 * Input redirectionrs
114 */
115str
116CMDcallString(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
117{
118 str *s;
119
120 (void) mb; /* fool compiler */
121 s = getArgReference_str(stk, pci, 1);
122 if (strlen(*s) == 0)
123 return MAL_SUCCEED;
124 return callString(cntxt, *s, FALSE);
125}
126
127str
128CMDcallFunction(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
129{
130 str mod = *getArgReference_str(stk,pci,1);
131 str fcn = *getArgReference_str(stk,pci,2);
132 char buf[BUFSIZ];
133
134 (void) mb; /* fool compiler */
135 if (strlen(mod) == 0 || strlen(fcn) ==0)
136 return MAL_SUCCEED;
137 // lazy implementation of the call
138 snprintf(buf,BUFSIZ,"%s.%s();",mod,fcn);
139 return callString(cntxt, buf, FALSE);
140}
141
142str
143MALstartDataflow( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
144{
145 bit *ret = getArgReference_bit(stk,pci,0);
146 int pc = getPC(mb,pci);
147
148 if ( pc <0 || pc > pci->jump)
149 throw(MAL,"language.dataflow","Illegal statement range");
150 *ret = 0; /* continue at end of block */
151 return runMALdataflow(cntxt, mb, pc, pci->jump, stk);
152}
153
154/*
155 * Garbage collection over variables can be postponed by grouping
156 * all dependent ones in a single sink() instruction.
157 */
158str
159MALgarbagesink( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
160{
161 (void) cntxt;
162 (void) mb;
163 (void) stk;
164 (void) pci;
165 return MAL_SUCCEED;
166}
167
168str
169MALpass( Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
170{
171 (void) cntxt;
172 (void) mb;
173 (void) stk;
174 (void) pci;
175 return MAL_SUCCEED;
176}
177
178str
179CMDregisterFunction(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
180{
181 Symbol sym= NULL;
182 str *mod = getArgReference_str(stk,pci,1);
183 str *fcn = getArgReference_str(stk,pci,2);
184 str *code = getArgReference_str(stk,pci,3);
185 str *help = getArgReference_str(stk,pci,4);
186 InstrPtr sig;
187 str msg, fcnName, modName, ahelp;
188
189 msg= compileString(&sym, cntxt,*code);
190 if( msg == MAL_SUCCEED) {
191 assert(cntxt->usermodule);
192 //mnstr_printf(cntxt->fdout,"#register FUNCTION %s.%s\n",
193 //getModuleId(sym->def->stmt[0]), getFunctionId(sym->def->stmt[0]));
194 mb= sym->def;
195 fcnName = putName(*fcn);
196 modName = putName(*mod);
197 ahelp = GDKstrdup(*help);
198 if(fcnName == NULL || modName == NULL || ahelp == NULL) {
199 freeSymbol(sym);
200 GDKfree(ahelp);
201 throw(MAL, "language.register", SQLSTATE(HY001) MAL_MALLOC_FAIL);
202 }
203 mb->help= ahelp;
204 sig= getSignature(sym);
205 sym->name= fcnName;
206 setModuleId(sig, modName);
207 setFunctionId(sig, sym->name);
208 insertSymbol(findModule(cntxt->usermodule, getModuleId(sig)), sym);
209 }
210 return msg;
211}
212str
213CMDevalFile(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
214{
215 str s = *getArgReference_str(stk,pci,1);
216 char *msg = NULL;
217 (void) mb;
218 (void) cntxt;
219
220 if (s == 0)
221 throw(MAL, "mal.evalFile", RUNTIME_FILE_NOT_FOUND "missing file name");
222
223 if (!MT_path_absolute(s)) {
224 char *buf = GDKmalloc(strlen(monet_cwd) + strlen(s) + 2);
225 if ( buf == NULL)
226 throw(MAL,"language.eval", SQLSTATE(HY001) MAL_MALLOC_FAIL);
227
228 stpcpy(stpcpy(stpcpy(buf, monet_cwd), DIR_SEP_STR), s);
229 msg = evalFile(buf, 0);
230 GDKfree(buf);
231 } else
232 msg = evalFile(s, 0);
233 return msg;
234}
235/*
236 * Calling a BAT is simply translated into a concatenation of
237 * all the unquoted strings and then passing it to the callEval.
238 */
239str
240CMDcallBAT(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
241{
242 (void) cntxt;
243 (void) mb;
244 (void) stk;
245 (void) pci; /* fool compiler */
246 throw(MAL, "mal.call", SQLSTATE(0A000) PROGRAM_NYI);
247}
248