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 * (author) M.L.Kersten
11 * Every MAL command introduced in an atom module should be checked
12 * to detect overloading of a predefined function.
13 * Subsequently, we update the GDK atom structure.
14 * The function signatures should be parameter-less, which
15 * enables additional functions with the same name to appear
16 * as ordinary mal operators.
17 *
18 * A few fields are set only once, at creation time.
19 * They should be implemented with parameter-less functions.
20 */
21#include "monetdb_config.h"
22#include "mal_instruction.h"
23#include "mal_atom.h"
24#include "mal_namespace.h"
25#include "mal_exception.h"
26#include "mal_private.h"
27
28static void setAtomName(InstrPtr pci)
29{
30 char buf[FILENAME_MAX];
31 snprintf(buf, FILENAME_MAX, "#%s", getFunctionId(pci));
32 setFunctionId(pci, putName(buf));
33}
34
35str
36malAtomProperty(MalBlkPtr mb, InstrPtr pci)
37{
38 str name;
39 int tpe;
40 (void)mb; /* fool compilers */
41 assert(pci != 0);
42 name = getFunctionId(pci);
43 tpe = getAtomIndex(getModuleId(pci), strlen(getModuleId(pci)), TYPE_any);
44 if (tpe < 0 || tpe >= GDKatomcnt || tpe >= MAXATOMS)
45 return MAL_SUCCEED;
46 assert(pci->fcn != NULL);
47 switch (name[0]) {
48 case 'd':
49 if (idcmp("del", name) == 0 && pci->argc == 1) {
50 BATatoms[tpe].atomDel = (void (*)(Heap *, var_t *))pci->fcn;
51 setAtomName(pci);
52 return MAL_SUCCEED;
53 }
54 break;
55 case 'c':
56 if (idcmp("cmp", name) == 0 && pci->argc == 1) {
57 BATatoms[tpe].atomCmp = (int (*)(const void *, const void *))pci->fcn;
58 BATatoms[tpe].linear = true;
59 setAtomName(pci);
60 return MAL_SUCCEED;
61 }
62 break;
63 case 'f':
64 if (idcmp("fromstr", name) == 0 && pci->argc == 1) {
65 BATatoms[tpe].atomFromStr = (ssize_t (*)(const char *, size_t *, ptr *, bool))pci->fcn;
66 setAtomName(pci);
67 return MAL_SUCCEED;
68 }
69 if (idcmp("fix", name) == 0 && pci->argc == 1) {
70 BATatoms[tpe].atomFix = (int (*)(const void *))pci->fcn;
71 setAtomName(pci);
72 return MAL_SUCCEED;
73 }
74 break;
75 case 'h':
76 if (idcmp("heap", name) == 0 && pci->argc == 1) {
77 /* heap function makes an atom varsized */
78 BATatoms[tpe].size = sizeof(var_t);
79 assert_shift_width(ATOMelmshift(ATOMsize(tpe)), ATOMsize(tpe));
80 BATatoms[tpe].atomHeap = (void (*)(Heap *, size_t))pci->fcn;
81 setAtomName(pci);
82 return MAL_SUCCEED;
83 }
84 if (idcmp("hash", name) == 0 && pci->argc == 1) {
85 BATatoms[tpe].atomHash = (BUN (*)(const void *))pci->fcn;
86 setAtomName(pci);
87 return MAL_SUCCEED;
88 }
89 break;
90 case 'l':
91 if (idcmp("length", name) == 0 && pci->argc == 1) {
92 BATatoms[tpe].atomLen = (size_t (*)(const void *))pci->fcn;
93 setAtomName(pci);
94 return MAL_SUCCEED;
95 }
96 break;
97 case 'n':
98 if (idcmp("null", name) == 0 && pci->argc == 1) {
99 const void *atmnull = ((const void *(*)(void))pci->fcn)();
100
101 BATatoms[tpe].atomNull = atmnull;
102 setAtomName(pci);
103 return MAL_SUCCEED;
104 }
105 if (idcmp("nequal", name) == 0 && pci->argc == 1) {
106 BATatoms[tpe].atomCmp = (int (*)(const void *, const void *))pci->fcn;
107 setAtomName(pci);
108 return MAL_SUCCEED;
109 }
110 break;
111 case 'p':
112 if (idcmp("put", name) == 0 && pci->argc == 1) {
113 BATatoms[tpe].atomPut = (var_t (*)(Heap *, var_t *, const void *))pci->fcn;
114 setAtomName(pci);
115 return MAL_SUCCEED;
116 }
117 break;
118 case 's':
119 if (idcmp("storage", name) == 0 && pci->argc == 1) {
120 BATatoms[tpe].storage = (*(int (*)(void))pci->fcn)();
121 setAtomName(pci);
122 return MAL_SUCCEED;
123 }
124 break;
125 case 't':
126 if (idcmp("tostr", name) == 0 && pci->argc == 1) {
127 BATatoms[tpe].atomToStr = (ssize_t (*)(str *, size_t *, const void *, bool))pci->fcn;
128 setAtomName(pci);
129 return MAL_SUCCEED;
130 }
131 break;
132 case 'u':
133 if (idcmp("unfix", name) == 0 && pci->argc == 1) {
134 BATatoms[tpe].atomUnfix = (int (*)(const void *))pci->fcn;
135 setAtomName(pci);
136 return MAL_SUCCEED;
137 }
138 break;
139 case 'r':
140 if (idcmp("read", name) == 0 && pci->argc == 1) {
141 BATatoms[tpe].atomRead = (void *(*)(void *, stream *, size_t))pci->fcn;
142 setAtomName(pci);
143 return MAL_SUCCEED;
144 }
145 break;
146 case 'w':
147 if (idcmp("write", name) == 0 && pci->argc == 1) {
148 BATatoms[tpe].atomWrite = (gdk_return (*)(const void *, stream *, size_t))pci->fcn;
149 setAtomName(pci);
150 return MAL_SUCCEED;
151 }
152 break;
153 }
154 return MAL_SUCCEED;
155}
156/*
157 * Atoms are constructed incrementally in the kernel using the
158 * ATOMallocate function. It takes an existing type as a base
159 * to derive a new one.
160 * The most tedisous work is to check the signature types of the functions
161 * acceptable for the kernel.
162 */
163
164str
165malAtomDefinition(str name, int tpe)
166{
167 int i;
168
169 if (strlen(name) >= IDLENGTH) {
170 throw (SYNTAX, "atomDefinition", "Atom name '%s' too long", name);
171 }
172 if (ATOMindex(name) >= 0) {
173#ifndef HAVE_EMBEDDED /* we can restart embedded MonetDB, making this an expected error */
174 throw(TYPE, "atomDefinition", "Redefinition of atom '%s'", name);
175#endif
176 }
177 if (tpe < 0 || tpe >= GDKatomcnt) {
178 throw(TYPE, "atomDefinition", "Undefined atom inheritance '%s'", name);
179 }
180 if (strlen(name) >= sizeof(BATatoms[0].name))
181 throw(TYPE, "atomDefinition", "Atom name too long '%s'", name);
182
183 i = ATOMallocate(name);
184 if (is_int_nil(i))
185 throw(TYPE,"atomDefinition", SQLSTATE(HY001) MAL_MALLOC_FAIL);
186 /* overload atom ? */
187 if (tpe) {
188 BATatoms[i] = BATatoms[tpe];
189 strcpy_len(BATatoms[i].name, name, sizeof(BATatoms[i].name));
190 BATatoms[i].storage = ATOMstorage(tpe);
191 } else { /* cannot overload void atoms */
192 BATatoms[i].storage = i;
193 BATatoms[i].linear = false;
194 }
195 return MAL_SUCCEED;
196}
197/*
198 * User defined modules may introduce fixed sized types
199 * to store information in BATs.
200 */
201int malAtomSize(int size, const char *name)
202{
203 int i = 0;
204
205 i = ATOMindex(name);
206 BATatoms[i].storage = i;
207 BATatoms[i].size = size;
208 assert_shift_width(ATOMelmshift(ATOMsize(i)), ATOMsize(i));
209 return i;
210}
211
212void
213mal_atom_reset(void)
214{
215 int i;
216 for( i = 0; i < GDKatomcnt; i++)
217 if( BATatoms[i].atomNull){
218 // TBD
219 }
220}
221