| 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 | |
| 28 | static 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 | |
| 35 | str |
| 36 | malAtomProperty(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 | |
| 164 | str |
| 165 | malAtomDefinition(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 | */ |
| 201 | int 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 | |
| 212 | void |
| 213 | mal_atom_reset(void) |
| 214 | { |
| 215 | int i; |
| 216 | for( i = 0; i < GDKatomcnt; i++) |
| 217 | if( BATatoms[i].atomNull){ |
| 218 | // TBD |
| 219 | } |
| 220 | } |
| 221 | |