1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2009-2016 Brazil
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License version 2.1 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#pragma once
20
21#include "grn.h"
22#include "grn_error.h"
23
24#include <errno.h>
25
26#ifdef HAVE_SIGNAL_H
27#include <signal.h>
28#define GRN_BREAK_POINT raise(SIGTRAP)
29#endif /* HAVE_SIGNAL_H */
30
31#ifdef HAVE_EXECINFO_H
32#include <execinfo.h>
33#endif /* HAVE_EXECINFO_H */
34
35#include "grn_io.h"
36#include "grn_alloc.h"
37#include "grn_time.h"
38
39#ifdef __cplusplus
40extern "C" {
41#endif
42
43/**** api in/out ****/
44
45#define GRN_API_ENTER do {\
46 if ((ctx)->seqno & 1) {\
47 (ctx)->subno++;\
48 } else {\
49 (ctx)->errlvl = GRN_OK;\
50 if ((ctx)->rc != GRN_CANCEL) {\
51 (ctx)->rc = GRN_SUCCESS;\
52 }\
53 (ctx)->seqno++;\
54 }\
55 GRN_TEST_YIELD();\
56} while (0)
57
58/* CAUTION!! : pass only variables or constants as r */
59#define GRN_API_RETURN(r) do {\
60 if (ctx->subno) {\
61 ctx->subno--;\
62 } else {\
63 ctx->seqno++;\
64 }\
65 GRN_TEST_YIELD();\
66 return r;\
67} while (0)
68
69/**** error handling ****/
70
71#define GRN_EMERG GRN_LOG_EMERG
72#define GRN_ALERT GRN_LOG_ALERT
73#define GRN_CRIT GRN_LOG_CRIT
74#define GRN_ERROR GRN_LOG_ERROR
75#define GRN_WARN GRN_LOG_WARNING
76#define GRN_OK GRN_LOG_NOTICE
77
78#define ERRCLR(ctx) do {\
79 if (ctx) {\
80 ((grn_ctx *)ctx)->errlvl = GRN_OK;\
81 if (((grn_ctx *)ctx)->rc != GRN_CANCEL) {\
82 ((grn_ctx *)ctx)->rc = GRN_SUCCESS;\
83 ((grn_ctx *)ctx)->errbuf[0] = '\0';\
84 }\
85 }\
86 errno = 0;\
87 grn_gctx.errlvl = GRN_OK;\
88 grn_gctx.rc = GRN_SUCCESS;\
89} while (0)
90
91#ifdef HAVE_BACKTRACE
92#define BACKTRACE(ctx) ((ctx)->ntrace = (unsigned char)backtrace((ctx)->trace, 16))
93#else /* HAVE_BACKTRACE */
94#define BACKTRACE(ctx)
95#endif /* HAVE_BACKTRACE */
96
97GRN_API grn_bool grn_ctx_impl_should_log(grn_ctx *ctx);
98GRN_API void grn_ctx_impl_set_current_error_message(grn_ctx *ctx);
99
100#ifdef HAVE_BACKTRACE
101#define LOGTRACE(ctx,lvl) do {\
102 int i;\
103 char **p;\
104 BACKTRACE(ctx);\
105 p = backtrace_symbols((ctx)->trace, (ctx)->ntrace);\
106 if (!p) {\
107 GRN_LOG((ctx), lvl, "backtrace_symbols failed");\
108 } else {\
109 for (i = 0; i < (ctx)->ntrace; i++) {\
110 GRN_LOG((ctx), lvl, "%s", p[i]);\
111 }\
112 free(p);\
113 }\
114} while (0)
115#else /* HAVE_BACKTRACE */
116#define LOGTRACE(ctx,msg)
117#endif /* HAVE_BACKTRACE */
118
119#define ERRSET(ctx,lvl,r,...) do {\
120 grn_ctx *ctx_ = (grn_ctx *)ctx;\
121 ctx_->errlvl = (lvl);\
122 if (ctx_->rc != GRN_CANCEL) {\
123 ctx_->rc = (r);\
124 }\
125 ctx_->errfile = __FILE__;\
126 ctx_->errline = __LINE__;\
127 ctx_->errfunc = __FUNCTION__;\
128 grn_ctx_log(ctx, __VA_ARGS__);\
129 if (grn_ctx_impl_should_log(ctx)) {\
130 grn_ctx_impl_set_current_error_message(ctx);\
131 GRN_LOG(ctx, lvl, __VA_ARGS__);\
132 if (lvl <= GRN_LOG_ERROR) { LOGTRACE(ctx, lvl); }\
133 }\
134} while (0)
135
136#define ERRP(ctx,lvl) \
137 (((ctx) && ((grn_ctx *)(ctx))->errlvl <= (lvl)) || (grn_gctx.errlvl <= (lvl)))
138
139#ifdef ERR
140# undef ERR
141#endif /* ERR */
142#define CRIT(rc,...) ERRSET(ctx, GRN_CRIT, (rc), __VA_ARGS__)
143#define ERR(rc,...) ERRSET(ctx, GRN_ERROR, (rc), __VA_ARGS__)
144#define WARN(rc,...) ERRSET(ctx, GRN_WARN, (rc), __VA_ARGS__)
145#define MERR(...) ERRSET(ctx, GRN_ALERT, GRN_NO_MEMORY_AVAILABLE, __VA_ARGS__)
146#define ALERT(...) ERRSET(ctx, GRN_ALERT, GRN_SUCCESS, __VA_ARGS__)
147
148#define ERR_CAST(column, range, element) do {\
149 grn_obj inspected;\
150 char column_name[GRN_TABLE_MAX_KEY_SIZE];\
151 int column_name_size;\
152 char range_name[GRN_TABLE_MAX_KEY_SIZE];\
153 int range_name_size;\
154 GRN_TEXT_INIT(&inspected, 0);\
155 grn_inspect(ctx, &inspected, element);\
156 column_name_size = grn_obj_name(ctx, column, column_name,\
157 GRN_TABLE_MAX_KEY_SIZE);\
158 range_name_size = grn_obj_name(ctx, range, range_name,\
159 GRN_TABLE_MAX_KEY_SIZE);\
160 ERR(GRN_INVALID_ARGUMENT, "<%.*s>: failed to cast to <%.*s>: <%.*s>",\
161 column_name_size, column_name,\
162 range_name_size, range_name,\
163 (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));\
164 GRN_OBJ_FIN(ctx, &inspected);\
165} while (0)
166
167#define USER_MESSAGE_SIZE 1024
168
169#ifdef WIN32
170
171#define SERR(...) do {\
172 grn_rc rc;\
173 int error_code;\
174 const char *system_message;\
175 char user_message[USER_MESSAGE_SIZE];\
176 error_code = GetLastError();\
177 system_message = grn_current_error_message();\
178 rc = grn_windows_error_code_to_rc(error_code);\
179 grn_snprintf(user_message,\
180 USER_MESSAGE_SIZE, USER_MESSAGE_SIZE,\
181 __VA_ARGS__);\
182 ERR(rc, "system error[%d]: %s: %s",\
183 error_code, system_message, user_message);\
184} while (0)
185
186#define SOERR(...) do {\
187 grn_rc rc;\
188 const char *m;\
189 char user_message[USER_MESSAGE_SIZE];\
190 int e = WSAGetLastError();\
191 switch (e) {\
192 case WSANOTINITIALISED :\
193 rc = GRN_SOCKET_NOT_INITIALIZED;\
194 m = "please call grn_com_init first";\
195 break;\
196 case WSAEFAULT :\
197 rc = GRN_BAD_ADDRESS;\
198 m = "bad address";\
199 break;\
200 case WSAEINVAL :\
201 rc = GRN_INVALID_ARGUMENT;\
202 m = "invalid argument";\
203 break;\
204 case WSAEMFILE :\
205 rc = GRN_TOO_MANY_OPEN_FILES;\
206 m = "too many sockets";\
207 break;\
208 case WSAEWOULDBLOCK :\
209 rc = GRN_OPERATION_WOULD_BLOCK;\
210 m = "operation would block";\
211 break;\
212 case WSAENOTSOCK :\
213 rc = GRN_NOT_SOCKET;\
214 m = "given fd is not socket fd";\
215 break;\
216 case WSAEOPNOTSUPP :\
217 rc = GRN_OPERATION_NOT_SUPPORTED;\
218 m = "operation is not supported";\
219 break;\
220 case WSAEADDRINUSE :\
221 rc = GRN_ADDRESS_IS_IN_USE;\
222 m = "address is already in use";\
223 break;\
224 case WSAEADDRNOTAVAIL :\
225 rc = GRN_ADDRESS_IS_NOT_AVAILABLE;\
226 m = "address is not available";\
227 break;\
228 case WSAENETDOWN :\
229 rc = GRN_NETWORK_IS_DOWN;\
230 m = "network is down";\
231 break;\
232 case WSAENOBUFS :\
233 rc = GRN_NO_BUFFER;\
234 m = "no buffer";\
235 break;\
236 case WSAEISCONN :\
237 rc = GRN_SOCKET_IS_ALREADY_CONNECTED;\
238 m = "socket is already connected";\
239 break;\
240 case WSAENOTCONN :\
241 rc = GRN_SOCKET_IS_NOT_CONNECTED;\
242 m = "socket is not connected";\
243 break;\
244 case WSAESHUTDOWN :\
245 rc = GRN_SOCKET_IS_ALREADY_SHUTDOWNED;\
246 m = "socket is already shutdowned";\
247 break;\
248 case WSAETIMEDOUT :\
249 rc = GRN_OPERATION_TIMEOUT;\
250 m = "connection time out";\
251 break;\
252 case WSAECONNREFUSED :\
253 rc = GRN_CONNECTION_REFUSED;\
254 m = "connection refused";\
255 break;\
256 case WSAEINTR :\
257 rc = GRN_INTERRUPTED_FUNCTION_CALL;\
258 m = "interrupted function call";\
259 break;\
260 default:\
261 rc = GRN_UNKNOWN_ERROR;\
262 m = "unknown error";\
263 break;\
264 }\
265 grn_snprintf(user_message,\
266 USER_MESSAGE_SIZE, USER_MESSAGE_SIZE,\
267 __VA_ARGS__);\
268 ERR(rc, "socket error[%d]: %s: %s",\
269 e, m, user_message);\
270} while (0)
271
272#define ERRNO_ERR(...) do {\
273 grn_rc rc;\
274 int errno_keep = errno;\
275 grn_bool show_errno = GRN_FALSE;\
276 const char *system_message;\
277 char user_message[USER_MESSAGE_SIZE];\
278 system_message = grn_strerror(errno);\
279 switch (errno_keep) {\
280 case EPERM : rc = GRN_OPERATION_NOT_PERMITTED; break;\
281 case ENOENT : rc = GRN_NO_SUCH_FILE_OR_DIRECTORY; break;\
282 case ESRCH : rc = GRN_NO_SUCH_PROCESS; break;\
283 case EINTR : rc = GRN_INTERRUPTED_FUNCTION_CALL; break;\
284 case EIO : rc = GRN_INPUT_OUTPUT_ERROR; break;\
285 case E2BIG : rc = GRN_ARG_LIST_TOO_LONG; break;\
286 case ENOEXEC : rc = GRN_EXEC_FORMAT_ERROR; break;\
287 case EBADF : rc = GRN_BAD_FILE_DESCRIPTOR; break;\
288 case ECHILD : rc = GRN_NO_CHILD_PROCESSES; break;\
289 case EAGAIN: rc = GRN_OPERATION_WOULD_BLOCK; break;\
290 case ENOMEM : rc = GRN_NO_MEMORY_AVAILABLE; break;\
291 case EACCES : rc = GRN_PERMISSION_DENIED; break;\
292 case EFAULT : rc = GRN_BAD_ADDRESS; break;\
293 case EEXIST : rc = GRN_FILE_EXISTS; break;\
294 /* case EXDEV : */\
295 case ENODEV : rc = GRN_NO_SUCH_DEVICE; break;\
296 case ENOTDIR : rc = GRN_NOT_A_DIRECTORY; break;\
297 case EISDIR : rc = GRN_IS_A_DIRECTORY; break;\
298 case EINVAL : rc = GRN_INVALID_ARGUMENT; break;\
299 case EMFILE : rc = GRN_TOO_MANY_OPEN_FILES; break;\
300 case ENOTTY : rc = GRN_INAPPROPRIATE_I_O_CONTROL_OPERATION; break;\
301 case EFBIG : rc = GRN_FILE_TOO_LARGE; break;\
302 case ENOSPC : rc = GRN_NO_SPACE_LEFT_ON_DEVICE; break;\
303 case ESPIPE : rc = GRN_INVALID_SEEK; break;\
304 case EROFS : rc = GRN_READ_ONLY_FILE_SYSTEM; break;\
305 case EMLINK : rc = GRN_TOO_MANY_LINKS; break;\
306 case EPIPE : rc = GRN_BROKEN_PIPE; break;\
307 case EDOM : rc = GRN_DOMAIN_ERROR; break;\
308 case ERANGE : rc = GRN_RANGE_ERROR; break;\
309 case EDEADLOCK : rc = GRN_RESOURCE_DEADLOCK_AVOIDED; break;\
310 case ENAMETOOLONG : rc = GRN_FILENAME_TOO_LONG; break;\
311 case EILSEQ : rc = GRN_ILLEGAL_BYTE_SEQUENCE; break;\
312 /* case STRUNCATE : */\
313 default :\
314 rc = GRN_UNKNOWN_ERROR;\
315 show_errno = GRN_TRUE;\
316 break;\
317 }\
318 grn_snprintf(user_message,\
319 USER_MESSAGE_SIZE, USER_MESSAGE_SIZE,\
320 __VA_ARGS__);\
321 if (show_errno) {\
322 ERR(rc, "system call error[%d]: %s: %s",\
323 errno_keep, system_message, user_message);\
324 } else {\
325 ERR(rc, "system call error: %s: %s",\
326 system_message, user_message);\
327 }\
328} while (0)
329
330#else /* WIN32 */
331
332#define SERR(...) do {\
333 grn_rc rc;\
334 int errno_keep = errno;\
335 grn_bool show_errno = GRN_FALSE;\
336 const char *system_message = grn_current_error_message();\
337 char user_message[USER_MESSAGE_SIZE];\
338 switch (errno_keep) {\
339 case ELOOP : rc = GRN_TOO_MANY_SYMBOLIC_LINKS; break;\
340 case ENAMETOOLONG : rc = GRN_FILENAME_TOO_LONG; break;\
341 case ENOENT : rc = GRN_NO_SUCH_FILE_OR_DIRECTORY; break;\
342 case ENOMEM : rc = GRN_NO_MEMORY_AVAILABLE; break;\
343 case ENOTDIR : rc = GRN_NOT_A_DIRECTORY; break;\
344 case EPERM : rc = GRN_OPERATION_NOT_PERMITTED; break;\
345 case ESRCH : rc = GRN_NO_SUCH_PROCESS; break;\
346 case EINTR : rc = GRN_INTERRUPTED_FUNCTION_CALL; break;\
347 case EIO : rc = GRN_INPUT_OUTPUT_ERROR; break;\
348 case ENXIO : rc = GRN_NO_SUCH_DEVICE_OR_ADDRESS; break;\
349 case E2BIG : rc = GRN_ARG_LIST_TOO_LONG; break;\
350 case ENOEXEC : rc = GRN_EXEC_FORMAT_ERROR; break;\
351 case EBADF : rc = GRN_BAD_FILE_DESCRIPTOR; break;\
352 case ECHILD : rc = GRN_NO_CHILD_PROCESSES; break;\
353 case EACCES : rc = GRN_PERMISSION_DENIED; break;\
354 case EFAULT : rc = GRN_BAD_ADDRESS; break;\
355 case EBUSY : rc = GRN_RESOURCE_BUSY; break;\
356 case EEXIST : rc = GRN_FILE_EXISTS; break;\
357 case ENODEV : rc = GRN_NO_SUCH_DEVICE; break;\
358 case EISDIR : rc = GRN_IS_A_DIRECTORY; break;\
359 case EINVAL : rc = GRN_INVALID_ARGUMENT; break;\
360 case EMFILE : rc = GRN_TOO_MANY_OPEN_FILES; break;\
361 case EFBIG : rc = GRN_FILE_TOO_LARGE; break;\
362 case ENOSPC : rc = GRN_NO_SPACE_LEFT_ON_DEVICE; break;\
363 case EROFS : rc = GRN_READ_ONLY_FILE_SYSTEM; break;\
364 case EMLINK : rc = GRN_TOO_MANY_LINKS; break;\
365 case EPIPE : rc = GRN_BROKEN_PIPE; break;\
366 case EDOM : rc = GRN_DOMAIN_ERROR; break;\
367 case ERANGE : rc = GRN_RANGE_ERROR; break;\
368 case ENOTSOCK : rc = GRN_NOT_SOCKET; break;\
369 case EADDRINUSE : rc = GRN_ADDRESS_IS_IN_USE; break;\
370 case ENETDOWN : rc = GRN_NETWORK_IS_DOWN; break;\
371 case ENOBUFS : rc = GRN_NO_BUFFER; break;\
372 case EISCONN : rc = GRN_SOCKET_IS_ALREADY_CONNECTED; break;\
373 case ENOTCONN : rc = GRN_SOCKET_IS_NOT_CONNECTED; break;\
374 /*\
375 case ESOCKTNOSUPPORT :\
376 case EOPNOTSUPP :\
377 case EPFNOSUPPORT :\
378 */\
379 case EPROTONOSUPPORT : rc = GRN_OPERATION_NOT_SUPPORTED; break;\
380 case ESHUTDOWN : rc = GRN_SOCKET_IS_ALREADY_SHUTDOWNED; break;\
381 case ETIMEDOUT : rc = GRN_OPERATION_TIMEOUT; break;\
382 case ECONNREFUSED: rc = GRN_CONNECTION_REFUSED; break;\
383 case EAGAIN: rc = GRN_OPERATION_WOULD_BLOCK; break;\
384 default :\
385 rc = GRN_UNKNOWN_ERROR;\
386 show_errno = GRN_TRUE;\
387 break;\
388 }\
389 grn_snprintf(user_message,\
390 USER_MESSAGE_SIZE, USER_MESSAGE_SIZE,\
391 __VA_ARGS__);\
392 if (show_errno) {\
393 ERR(rc, "system call error[%d]: %s: %s",\
394 errno_keep, system_message, user_message);\
395 } else {\
396 ERR(rc, "system call error: %s: %s",\
397 system_message, user_message);\
398 }\
399} while (0)
400
401#define SOERR(...) SERR(__VA_ARGS__)
402
403#define ERRNO_ERR(...) SERR(__VA_ARGS__)
404
405#endif /* WIN32 */
406
407#define GERR(rc,...) ERRSET(&grn_gctx, GRN_ERROR, (rc), __VA_ARGS__)
408#define GMERR(...) ERRSET(&grn_gctx, GRN_ALERT, GRN_NO_MEMORY_AVAILABLE, __VA_ARGS__)
409
410#ifdef DEBUG
411#define GRN_ASSERT(s) grn_assert(ctx,(s),__FILE__,__LINE__,__FUNCTION__)
412#else
413#define GRN_ASSERT(s)
414#endif
415
416void grn_assert(grn_ctx *ctx, int cond, const char* file, int line, const char* func);
417
418/**** grn_ctx ****/
419
420GRN_VAR grn_ctx grn_gctx;
421extern int grn_pagesize;
422extern grn_critical_section grn_glock;
423extern uint32_t grn_gtick;
424extern int grn_lock_timeout;
425
426#define GRN_CTX_ALLOCATED (0x80)
427#define GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND (0x40)
428
429extern grn_timeval grn_starttime;
430
431GRN_API void grn_ctx_log(grn_ctx *ctx, const char *fmt, ...) GRN_ATTRIBUTE_PRINTF(2);
432GRN_API void grn_ctx_logv(grn_ctx *ctx, const char *fmt, va_list ap);
433void grn_ctx_loader_clear(grn_ctx *ctx);
434void grn_log_reopen(grn_ctx *ctx);
435
436GRN_API grn_rc grn_ctx_sendv(grn_ctx *ctx, int argc, char **argv, int flags);
437void grn_ctx_set_keep_command(grn_ctx *ctx, grn_obj *command);
438
439grn_content_type grn_get_ctype(grn_obj *var);
440grn_content_type grn_content_type_parse(grn_ctx *ctx,
441 grn_obj *var,
442 grn_content_type default_value);
443
444/**** db_obj ****/
445
446/* flag values used for grn_obj.header.impl_flags */
447
448#define GRN_OBJ_ALLOCATED (0x01<<2) /* allocated by ctx */
449#define GRN_OBJ_EXPRVALUE (0x01<<3) /* value allocated by grn_expr */
450#define GRN_OBJ_EXPRCONST (0x01<<4) /* constant allocated by grn_expr */
451
452typedef struct _grn_hook grn_hook;
453
454typedef struct {
455 grn_obj_header header;
456 grn_id range; /* table: type of subrecords, column: type of values */
457 /* -- compatible with grn_accessor -- */
458 grn_id id;
459 grn_obj *db;
460 grn_user_data user_data;
461 grn_proc_func *finalizer;
462 grn_hook *hooks[5];
463 void *source;
464 uint32_t source_size;
465 uint32_t max_n_subrecs;
466 uint8_t subrec_size;
467 uint8_t subrec_offset;
468 uint8_t record_unit;
469 uint8_t subrec_unit;
470 union {
471 grn_table_group_flags group;
472 } flags;
473 // grn_obj_flags flags;
474} grn_db_obj;
475
476#define GRN_DB_OBJ_SET_TYPE(db_obj,obj_type) do {\
477 (db_obj)->obj.header.type = (obj_type);\
478 (db_obj)->obj.header.impl_flags = 0;\
479 (db_obj)->obj.header.flags = 0;\
480 (db_obj)->obj.header.domain = GRN_ID_NIL;\
481 (db_obj)->obj.id = GRN_ID_NIL;\
482 (db_obj)->obj.user_data.ptr = NULL;\
483 (db_obj)->obj.finalizer = NULL;\
484 (db_obj)->obj.hooks[0] = NULL;\
485 (db_obj)->obj.hooks[1] = NULL;\
486 (db_obj)->obj.hooks[2] = NULL;\
487 (db_obj)->obj.hooks[3] = NULL;\
488 (db_obj)->obj.hooks[4] = NULL;\
489 (db_obj)->obj.source = NULL;\
490 (db_obj)->obj.source_size = 0;\
491} while (0)
492
493/**** receive handler ****/
494
495GRN_API void grn_ctx_stream_out_func(grn_ctx *c, int flags, void *stream);
496
497grn_rc grn_db_init_builtin_procs(grn_ctx *ctx);
498
499#ifdef __cplusplus
500}
501#endif
502