1 //-< CLI.CPP >-------------------------------------------------------*--------*
2 // GigaBASE Version 1.0 (c) 1999 GARRET * ? *
3 // (Post Relational Database Management System) * /\| *
4 // * / \ *
5 // Created: 13-Jan-2000 K.A. Knizhnik * / [] \ *
6 // Last update: 13-Jan-2000 K.A. Knizhnik * GARRET *
7 //-------------------------------------------------------------------*--------*
8 // Call level interface client part implementation
9 //-------------------------------------------------------------------*--------*
10
11 #define INSIDE_GIGABASE
12
13 #include "stdtp.h"
14 #include "sockio.h"
15 #include "repsock.h"
16 #include "sync.h"
17 #include "cli.h"
18 #include "cliproto.h"
19
20 BEGIN_GIGABASE_NAMESPACE
21 struct parameter_binding {
22 parameter_binding* next;
23 char_t* name;
24 int var_type;
25 int var_len;
26 void* var_ptr;
27
~parameter_bindingparameter_binding28 ~parameter_binding() {
29 delete[] name;
30 }
31 };
32
33 struct column_binding {
34 column_binding* next;
35 char_t* name;
36 int var_type;
37 int* var_len;
38 void* var_ptr;
39 void* arr_ptr;
40 int arr_len;
41 cli_column_get_ex get_fnc;
42 cli_column_set_ex set_fnc;
43 void* user_data;
44
~column_bindingcolumn_binding45 ~column_binding() {
46 delete[] name;
47 }
48 };
49
50 struct session_desc;
51
52 #define DEFAULT_BUF_SIZE 256
53
54 struct statement_desc {
55 int id;
56 statement_desc* next;
57 char_t* stmt;
58 column_binding* columns;
59 parameter_binding* params;
60 session_desc* session;
61 int cursor_type;
62 bool prepared;
63 bool updated;
64 bool autoincrement;
65 cli_oid_t oid;
66 int stmt_len;
67 int n_params;
68 int n_columns;
69 int columns_len;
70 char* buf;
71 size_t buf_size;
72
freestatement_desc73 void free() {
74 delete[] stmt;
75 column_binding *cb, *next_cb;
76 for (cb = columns; cb != NULL; cb = next_cb) {
77 next_cb = cb->next;
78 delete cb;
79 }
80 if (buf != NULL) {
81 delete[] buf;
82 buf_size = 0;
83 buf = NULL;
84 }
85 parameter_binding *pb, *next_pb;
86 for (pb = params; pb != NULL; pb = next_pb) {
87 next_pb = pb->next;
88 delete pb;
89 }
90 }
statement_descstatement_desc91 statement_desc(int id, statement_desc* next) {
92 this->id = id;
93 this->next = next;
94 buf = NULL;
95 buf_size = 0;
96 }
statement_descstatement_desc97 statement_desc() {}
98 };
99
100 class connection_pool;
101
102 struct session_desc {
103 int id;
104 session_desc* next;
105 socket_t* sock;
106 statement_desc* stmts;
107
108 session_desc* next_pooled;
109 char_t* user;
110 char_t* password;
111 connection_pool* pool;
112
session_descsession_desc113 session_desc(int id, session_desc* next) {
114 this->id = id;
115 this->next = next;
116 pool = NULL;
117 }
session_descsession_desc118 session_desc() {}
119 };
120
121 template<class T>
122 class descriptor_table {
123 protected:
124 T** table;
125 T* free_desc;
126 int descriptor_table_size;
127 dbMutex mutex;
128
129 public:
descriptor_table()130 descriptor_table() {
131 descriptor_table_size = 16;
132 table = new T*[descriptor_table_size];
133 T* next = NULL;
134 for (int i = 0; i < descriptor_table_size; i++) {
135 table[i] = next = new T(i, next);
136 }
137 free_desc = next;
138 }
139
~descriptor_table()140 ~descriptor_table() {
141 for (int i = 0; i < descriptor_table_size; i++) {
142 delete table[i];
143 }
144 delete[] table;
145 }
146
get(int desc)147 T* get(int desc) {
148 dbCriticalSection cs(mutex);
149 return (desc >= descriptor_table_size) ? (T*)0 : table[desc];
150 }
151
allocate()152 T* allocate() {
153 dbCriticalSection cs(mutex);
154 if (free_desc == NULL) {
155 int i, n;
156 T** desc = new T*[descriptor_table_size * 2];
157 memcpy(desc, table, descriptor_table_size*sizeof(T*));
158 delete[] table;
159 table = desc;
160 T* next = NULL;
161 for (i = descriptor_table_size, n = i*2; i < n; i++) {
162 table[i] = next = new T(i, next);
163 }
164 free_desc = next;
165 descriptor_table_size = n;
166 }
167 T* desc = free_desc;
168 free_desc = desc->next;
169 return desc;
170 }
171
free(T * desc)172 void free(T* desc) {
173 dbCriticalSection cs(mutex);
174 desc->next = free_desc;
175 free_desc = desc;
176 }
177 };
178
179 static descriptor_table<session_desc> sessions;
180 static descriptor_table<statement_desc> statements;
181
cli_close_internal(session_desc * s)182 static int cli_close_internal(session_desc* s)
183 {
184 statement_desc *stmt, *next;
185 cli_request req;
186 req.length = sizeof(req);
187 req.cmd = cli_cmd_close_session;
188 req.stmt_id = 0;
189 req.pack();
190 int result = cli_ok;
191 if (!s->sock->write(&req, sizeof req)) {
192 result = cli_network_error;
193 }
194 delete s->sock;
195 s->sock = NULL;
196 for (stmt = s->stmts; stmt != NULL; stmt = next) {
197 next = stmt->next;
198 stmt->free();
199 statements.free(stmt);
200 }
201 sessions.free(s);
202 return result;
203 }
204
205 class connection_pool {
206 session_desc* connection_chain;
207 dbMutex mutex;
208
209 public:
connection_pool()210 connection_pool() {
211 connection_chain = NULL;
212 }
213
~connection_pool()214 ~connection_pool() {
215 close();
216 }
217
new_connection(char const * server_url,char_t const * user_name,char_t const * password)218 session_desc* new_connection(char const* server_url,
219 char_t const* user_name,
220 char_t const* password)
221 {
222 dbCriticalSection cs(mutex);
223 for (session_desc* desc = connection_chain; desc != NULL; desc = desc->next_pooled) {
224 if (strcmp(desc->sock->address, server_url) == 0 &&
225 STRCMP(desc->user, user_name) == 0 &&
226 STRCMP(desc->password, password) == 0)
227 {
228 connection_chain = desc->next_pooled;
229 return desc;
230 }
231 }
232 return NULL;
233 }
234
release(session_desc * desc)235 void release(session_desc* desc)
236 {
237 dbCriticalSection cs(mutex);
238 desc->next_pooled = connection_chain;
239 connection_chain = desc;
240 }
241
close()242 void close() {
243 dbCriticalSection cs(mutex);
244 session_desc *desc, *next;
245 for (desc = connection_chain; desc != NULL; desc = next) {
246 desc->pool = NULL;
247 delete[] desc->user;
248 delete[] desc->password;
249 next = desc->next_pooled;
250 cli_close_internal(desc);
251 }
252 connection_chain = NULL;
253 }
254 };
255
256 static connection_pool connections;
257
258 END_GIGABASE_NAMESPACE
259 USE_GIGABASE_NAMESPACE
260
cli_open(char const * server_url,int max_connect_attempts,int reconnect_timeout_sec,char_t const * user_name,char_t const * password,int pooled_connection)261 int cli_open(char const* server_url,
262 int max_connect_attempts,
263 int reconnect_timeout_sec,
264 char_t const* user_name,
265 char_t const* password,
266 int pooled_connection)
267 {
268 if (pooled_connection) {
269 session_desc* session = connections.new_connection(server_url, user_name, password);
270 if (session != NULL) {
271 return session->id;
272 }
273 }
274 socket_t* sock;
275 int n_addresses = 1;
276 char const* start = server_url;
277 char const* end;
278 while ((end = strchr(start, ',')) != NULL) {
279 start = end + 1;
280 n_addresses += 1;
281 }
282 if (n_addresses == 1) {
283 sock = socket_t::connect(server_url,
284 socket_t::sock_any_domain,
285 max_connect_attempts,
286 reconnect_timeout_sec);
287 } else {
288 char** addresses = new char*[n_addresses];
289 start = server_url;
290 for (int i = 0; i < n_addresses; i++) {
291 end = strchr(start, ',');
292 if (end == NULL) {
293 end = start + strlen(start);
294 }
295 int len = (int)(end - start);
296 char* addr = new char[len+1];
297 memcpy(addr, start, len);
298 addr[len] = '\0';
299 start = end + 1;
300 addresses[i] = addr;
301 }
302 sock = replication_socket_t::connect((char const**)addresses,
303 n_addresses,
304 max_connect_attempts,
305 reconnect_timeout_sec);
306 while (--n_addresses >= 0) {
307 delete[] addresses[n_addresses];
308 }
309 delete[] addresses;
310 }
311
312 if (!sock->is_ok()) {
313 char_t buf[256];
314 sock->get_error_text(buf, itemsof(buf));
315 fprintf(stderr, "Failed to connect to server: %s\n", buf);
316 delete sock;
317 return cli_connection_refused;
318 }
319 size_t msg_size = sizeof(cli_request) + (STRLEN(user_name) + STRLEN(password) + 2)*sizeof(char_t);
320
321 dbSmallBuffer<char> buf(msg_size);
322 char* p = buf;
323 cli_request* req = (cli_request*)p;
324 req->length = (int4)msg_size;
325 req->cmd = cli_cmd_login;
326 req->stmt_id = 0;
327 p += sizeof(cli_request);
328 p = pack_str(p, user_name);
329 p = pack_str(p, password);
330 req->pack();
331 if (sock->write(req, msg_size)) {
332 int4 response;
333 if (!sock->read(&response, sizeof response)) {
334 return cli_network_error;
335 }
336 unpack4(response);
337 if (response == cli_ok) {
338 session_desc* session = sessions.allocate();
339 session->sock = sock;
340 session->stmts = NULL;
341 if (pooled_connection) {
342 session->pool = &connections;
343 session->user = new char_t[STRLEN(user_name)+1];
344 STRCPY(session->user, user_name);
345 session->password = new char_t[STRLEN(password)+1];
346 STRCPY(session->password, password);
347 }
348 return session->id;
349 }
350 return response;
351 } else {
352 return cli_network_error;
353 }
354 }
355
356
cli_close(int session)357 int cli_close(int session)
358 {
359 session_desc* s = sessions.get(session);
360 if (s == NULL) {
361 return cli_bad_descriptor;
362 }
363 if (s->pool != NULL) {
364 s->pool->release(s);
365 return cli_ok;
366 }
367 return cli_close_internal(s);
368 }
369
cli_clear_connection_pool()370 void cli_clear_connection_pool()
371 {
372 connections.close();
373 }
374
375
cli_statement(int session,char_t const * stmt_str)376 int cli_statement(int session, char_t const* stmt_str)
377 {
378 session_desc* s = sessions.get(session);
379 if (s == NULL) {
380 return cli_bad_descriptor;
381 }
382 statement_desc* stmt = statements.allocate();
383 stmt->stmt = new char_t[STRLEN(stmt_str)+1];
384 stmt->columns = NULL;
385 stmt->params = NULL;
386 stmt->session = s;
387 stmt->cursor_type = cli_cursor_view_only;
388 stmt->prepared = false;
389 stmt->n_params = 0;
390 stmt->n_columns = 0;
391 stmt->columns_len = 0;
392 stmt->oid = 0;
393 stmt->next = s->stmts;
394 stmt->updated = false;
395 s->stmts = stmt;
396 char_t const* p = stmt_str;
397 char_t* dst = stmt->stmt;
398 parameter_binding** last = &stmt->params;
399 while (*p != '\0') {
400 if (*p == '\'') {
401 do {
402 do {
403 *dst++ = *p++;
404 } while (*p != '\0' && *p != '\'');
405 *dst++ = *p;
406 if (*p == '\0') {
407 *last = NULL;
408 stmt->free();
409 statements.free(stmt);
410 return cli_bad_statement;
411 }
412 } while (*++p == '\'');
413 } else if (*p == '%') {
414 stmt->n_params += 1;
415 char_t const* q = p++;
416 while (ISALNUM(*p) || *p == '_') p += 1;
417 if (*p == '%') {
418 *last = NULL;
419 stmt->free();
420 statements.free(stmt);
421 return cli_bad_statement;
422 }
423 parameter_binding* pb = new parameter_binding;
424 int len = (int)(p - q);
425 pb->name = new char_t[len+1];
426 memcpy(pb->name, q, len*sizeof(char_t));
427 pb->name[len] = '\0';
428 *last = pb;
429 last = &pb->next;
430 pb->var_ptr = NULL;
431 *dst++ = '\0';
432 } else {
433 *dst++ = *p++;
434 }
435 }
436 if (dst == stmt->stmt || *(dst-1) != '\0') {
437 *dst++ = '\0';
438 }
439 stmt->stmt_len = (int)(dst - stmt->stmt);
440 *last = NULL;
441 return stmt->id;
442 }
443
cli_parameter(int statement,char_t const * param_name,int var_type,void * var_ptr)444 int cli_parameter(int statement,
445 char_t const* param_name,
446 int var_type,
447 void* var_ptr)
448 {
449 if (var_type != cli_rectangle
450 && ((unsigned)var_type >= cli_array_of_oid || var_type == cli_decimal))
451 {
452 return cli_unsupported_type;
453 }
454 statement_desc* s = statements.get(statement);
455 if (s == NULL) {
456 return cli_bad_descriptor;
457 }
458 s->prepared = false;
459 for (parameter_binding* pb = s->params; pb != NULL; pb = pb->next) {
460 if (STRCMP(pb->name, param_name) == 0) {
461 pb->var_ptr = var_ptr;
462 pb->var_type = var_type;
463 return cli_ok;
464 }
465 }
466 return cli_parameter_not_found;
467 }
468
cli_column(int statement,char_t const * column_name,int var_type,int * var_len,void * var_ptr)469 int cli_column(int statement,
470 char_t const* column_name,
471 int var_type,
472 int* var_len,
473 void* var_ptr)
474 {
475 statement_desc* s = statements.get(statement);
476 if (s == NULL) {
477 return cli_bad_descriptor;
478 }
479 if (var_type == cli_decimal || var_type == cli_array_of_decimal
480 || (unsigned)var_type >= cli_unknown)
481 {
482 return cli_unsupported_type;
483 }
484 s->prepared = false;
485 column_binding* cb = new column_binding;
486 int len = (int)STRLEN(column_name) + 1;
487 cb->name = new char_t[len];
488 s->columns_len += len;
489 cb->next = s->columns;
490 s->columns = cb;
491 s->n_columns += 1;
492 STRCPY(cb->name, column_name);
493 cb->var_type = var_type;
494 cb->var_len = var_len;
495 cb->var_ptr = var_ptr;
496 cb->set_fnc = NULL;
497 cb->get_fnc = NULL;
498 return cli_ok;
499 }
500
cli_array_column(int statement,char_t const * column_name,int var_type,void * var_ptr,cli_column_set set,cli_column_get get)501 int cli_array_column(int statement,
502 char_t const* column_name,
503 int var_type,
504 void* var_ptr,
505 cli_column_set set,
506 cli_column_get get)
507 {
508 return cli_array_column_ex(statement, column_name, var_type, var_ptr,
509 (cli_column_set_ex)set, (cli_column_get_ex)get, NULL);
510 }
511
cli_array_column_ex(int statement,char_t const * column_name,int var_type,void * var_ptr,cli_column_set_ex set,cli_column_get_ex get,void * user_data)512 int cli_array_column_ex(int statement,
513 char_t const* column_name,
514 int var_type,
515 void* var_ptr,
516 cli_column_set_ex set,
517 cli_column_get_ex get,
518 void* user_data)
519 {
520 statement_desc* s = statements.get(statement);
521 if (s == NULL) {
522 return cli_bad_descriptor;
523 }
524 if (var_type < cli_asciiz || var_type > cli_array_of_string || var_type == cli_array_of_decimal) {
525 return cli_unsupported_type;
526 }
527 s->prepared = false;
528 column_binding* cb = new column_binding;
529 int len = (int)STRLEN(column_name) + 1;
530 cb->name = new char_t[len];
531 s->columns_len += len;
532 cb->next = s->columns;
533 s->columns = cb;
534 s->n_columns += 1;
535 STRCPY(cb->name, column_name);
536 cb->var_type = var_type;
537 cb->var_len = NULL;
538 cb->var_ptr = var_ptr;
539 cb->set_fnc = set;
540 cb->get_fnc = get;
541 cb->user_data = user_data;
542 return cli_ok;
543 }
544
cli_fetch_ex(int statement,int cursor_type,cli_cardinality_t * n_fetched_records)545 int cli_fetch_ex(int statement, int cursor_type, cli_cardinality_t* n_fetched_records)
546 {
547 int rc = cli_fetch(statement, cursor_type);
548 if (rc >= 0) {
549 *n_fetched_records = rc;
550 return cli_ok;
551 }
552 return rc;
553 }
554
cli_fetch(int statement,int cursor_type)555 int cli_fetch(int statement, int cursor_type)
556 {
557 parameter_binding* pb;
558 column_binding* cb;
559 statement_desc* stmt = statements.get(statement);
560 char *p;
561
562 if (stmt == NULL) {
563 return cli_bad_descriptor;
564 }
565 stmt->cursor_type = cursor_type;
566 int msg_size = sizeof(cli_request) + 1;
567 if (!stmt->prepared) {
568 msg_size += 4 + stmt->stmt_len*sizeof(char_t) + stmt->n_params;
569 msg_size += stmt->columns_len*sizeof(char_t) + stmt->n_columns;
570 }
571 for (pb = stmt->params; pb != NULL; pb = pb->next) {
572 if (pb->var_ptr == NULL) {
573 return cli_unbound_parameter;
574 }
575 if (pb->var_type == cli_asciiz) {
576 msg_size += (int)((-msg_size & (sizeof(char_t)-1)) + (STRLEN((char_t*)pb->var_ptr) + 1)*sizeof(char_t));
577 } else if (pb->var_type == cli_pasciiz) {
578 msg_size += (int)((-msg_size & (sizeof(char_t)-1)) + (STRLEN(*(char_t**)pb->var_ptr) + 1)*sizeof(char_t));
579 } else if (pb->var_type == cli_cstring) {
580 msg_size += (int)(((cli_cstring_t*)pb->var_ptr)->len*sizeof(char_t) + 4);
581 } else {
582 msg_size += sizeof_type[pb->var_type];
583 }
584 }
585 stmt->oid = 0;
586 dbSmallBuffer<char> buf(msg_size);
587 p = buf;
588 cli_request* req = (cli_request*)p;
589 req->length = msg_size;
590 req->cmd = stmt->prepared
591 ? cli_cmd_execute : cli_cmd_prepare_and_execute;
592 req->stmt_id = statement;
593 p += sizeof(cli_request);
594
595 if (!stmt->prepared) {
596 *p++ = stmt->n_params;
597 *p++ = stmt->n_columns;
598 p = pack2(p, (int2)(stmt->stmt_len*sizeof(char_t) + stmt->n_params));
599 pb = stmt->params;
600 char* end = p + stmt->stmt_len*sizeof(char_t) + stmt->n_params;
601 char_t* src = stmt->stmt;
602 while (p < end) {
603 char* q = pack_str(p, src);
604 src += (q - p)/sizeof(char_t);
605 p = q;
606 if (pb != NULL) {
607 *p++ = pb->var_type == cli_pasciiz ? cli_asciiz : pb->var_type;
608 pb = pb->next;
609 }
610 }
611 for (cb = stmt->columns; cb != NULL; cb = cb->next) {
612 *p++ = cb->var_type;
613 p = pack_str(p, cb->name);
614 }
615 }
616 *p++ = cursor_type;
617 for (pb = stmt->params; pb != NULL; pb = pb->next) {
618 switch (pb->var_type) {
619 case cli_asciiz:
620 p += -(int)(size_t)p & (sizeof(char_t)-1);
621 p = pack_str(p, (char_t*)pb->var_ptr);
622 continue;
623 case cli_rectangle:
624 p = pack_rectangle(p, (cli_rectangle_t*)pb->var_ptr);
625 continue;
626 case cli_pasciiz:
627 p += -(int)(size_t)p & (sizeof(char_t)-1);
628 p = pack_str(p, *(char_t**)pb->var_ptr);
629 continue;
630 case cli_cstring:
631 {
632 int len = ((cli_cstring_t*)pb->var_ptr)->len;
633 p = pack4(p, len);
634 p = pack_str(p, ((cli_cstring_t*)pb->var_ptr)->ptr, len);
635 continue;
636 }
637 default:
638 switch (sizeof_type[pb->var_type]) {
639 case 1:
640 *p++ = *(char*)pb->var_ptr;
641 continue;
642 case 2:
643 p = pack2(p, *(int2*)pb->var_ptr);
644 continue;
645 case 4:
646 p = pack4(p, *(int4*)pb->var_ptr);
647 continue;
648 case 8:
649 p = pack8(p, *(db_int8*)pb->var_ptr);
650 continue;
651 }
652 }
653 }
654 assert(msg_size == p - buf.base());
655 req->pack();
656 if (!stmt->session->sock->write(buf, msg_size)) {
657 return cli_network_error;
658 }
659 int4 response;
660 if (!stmt->session->sock->read(&response, sizeof response)) {
661 return cli_network_error;
662 }
663 unpack4(response);
664 if (response >= 0) {
665 stmt->prepared = true;
666 }
667 return response;
668 }
669
cli_send_columns(int statement,int cmd)670 static int cli_send_columns(int statement, int cmd)
671 {
672 statement_desc* s = statements.get(statement);
673 column_binding* cb;
674 int len;
675 if (s == NULL) {
676 return cli_bad_descriptor;
677 }
678 size_t msg_size = sizeof(cli_request);
679 if (cmd == cli_cmd_update) {
680 if (!s->prepared) {
681 return cli_not_fetched;
682 }
683 if (s->oid == 0) {
684 return cli_not_found;
685 }
686 if (s->updated) {
687 return cli_already_updated;
688 }
689 if (s->cursor_type != cli_cursor_for_update) {
690 return cli_not_update_mode;
691 }
692 } else {
693 if (!s->prepared) {
694 cmd = cli_cmd_prepare_and_insert;
695 msg_size += 1 + s->stmt_len*sizeof(char_t) + s->n_columns + s->columns_len*sizeof(char_t);
696 }
697 }
698 s->autoincrement = false;
699 for (cb = s->columns; cb != NULL; cb = cb->next) {
700 if (cb->get_fnc != NULL) {
701 cb->arr_ptr = cb->get_fnc(cb->var_type, cb->var_ptr, &cb->arr_len,
702 cb->name, statement, cb->user_data);
703 len = cb->arr_len;
704 msg_size += 4;
705 if (cb->var_type == cli_array_of_string) {
706 char_t** p = (char_t**)cb->arr_ptr;
707 while (--len >= 0) {
708 msg_size += (STRLEN(*p++) + 1)*sizeof(char_t);
709 }
710 } else if (cb->var_type >= cli_array_of_oid) {
711 msg_size += len * sizeof_type[cb->var_type - cli_array_of_oid];
712 } else {
713 msg_size += len;
714 }
715 } else {
716 switch (cb->var_type) {
717 case cli_autoincrement:
718 s->autoincrement = true;
719 break;
720 case cli_asciiz:
721 msg_size += 4 + (STRLEN((char_t*)cb->var_ptr) + 1)*sizeof(char_t);
722 break;
723 case cli_pasciiz:
724 msg_size += 4 + (STRLEN(*(char_t**)cb->var_ptr) + 1)*sizeof(char_t);
725 break;
726 case cli_cstring:
727 msg_size += 4 + ((cli_cstring_t*)cb->var_ptr)->len*sizeof(char_t);
728 break;
729 case cli_array_of_string:
730 {
731 char_t** p = (char_t**)cb->var_ptr;
732 msg_size += 4;
733 for (len = *cb->var_len; --len >= 0;) {
734 msg_size += (STRLEN(*p++) + 1)*sizeof(char_t);
735 }
736 break;
737 }
738 default:
739 if (cb->var_type >= cli_array_of_oid && cb->var_type < cli_array_of_string) {
740 msg_size += 4 + *cb->var_len * sizeof_type[cb->var_type-cli_array_of_oid];
741 } else {
742 msg_size += sizeof_type[cb->var_type];
743 }
744 }
745 }
746 }
747 dbSmallBuffer<char> buf(msg_size);
748 char* p = buf;
749 cli_request* req = (cli_request*)p;
750 req->length = (int4)msg_size;
751 req->cmd = cmd;
752 req->stmt_id = statement;
753 p += sizeof(cli_request);
754 if (cmd == cli_cmd_prepare_and_insert) {
755 p = pack_str(p, s->stmt);
756 *p++ = s->n_columns;
757 for (cb = s->columns; cb != NULL; cb = cb->next) {
758 *p++ = cb->var_type;
759 p = pack_str(p, cb->name);
760 }
761 }
762 for (cb = s->columns; cb != NULL; cb = cb->next) {
763 int n = 0;
764 char* src;
765 if (cb->get_fnc != NULL) {
766 src = (char*)cb->arr_ptr;
767 n = cb->arr_len;
768 } else {
769 src = (char*)cb->var_ptr;
770 if (cb->var_type >= cli_array_of_oid && cb->var_type <= cli_array_of_string) {
771 n = *cb->var_len;
772 }
773 }
774 if (cb->var_type >= cli_array_of_oid && cb->var_type <= cli_array_of_string) {
775 p = pack4(p, n);
776 if (cb->var_type == cli_array_of_string) {
777 while (--n >= 0) {
778 p = pack_str(p, *(char_t**)src);
779 src += sizeof(char_t*);
780 }
781 } else {
782 switch (sizeof_type[cb->var_type-cli_array_of_oid]) {
783 case 2:
784 while (--n >= 0) {
785 p = pack2(p, src);
786 src += 2;
787 }
788 break;
789 case 4:
790 while (--n >= 0) {
791 p = pack4(p, src);
792 src += 4;
793 }
794 break;
795 case 8:
796 while (--n >= 0) {
797 p = pack8(p, src);
798 src += 8;
799 }
800 break;
801 default:
802 memcpy(p, src, n);
803 p += n;
804 }
805 }
806 } else if (cb->var_type == cli_asciiz) {
807 p = pack4(p, (int4)STRLEN((char_t*)src)+1);
808 p = pack_str(p, (char_t*)src);
809 } else if (cb->var_type == cli_cstring) {
810 int len = ((cli_cstring_t*)src)->len;
811 p = pack4(p, len);
812 p = pack_str(p, ((cli_cstring_t*)src)->ptr, len);
813 } else if (cb->var_type == cli_pasciiz) {
814 src = *(char**)src;
815 p = pack4(p, (int4)STRLEN((char_t*)src)+1);
816 p = pack_str(p, (char_t*)src);
817 } else if (cb->var_type == cli_rectangle) {
818 p = pack_rectangle(p, (cli_rectangle_t*)src);
819 } else if (cb->var_type != cli_autoincrement) {
820 switch (sizeof_type[cb->var_type]) {
821 case 2:
822 p = pack2(p, src);
823 break;
824 case 4:
825 p = pack4(p, src);
826 break;
827 case 8:
828 p = pack8(p, src);
829 break;
830 default:
831 *p++ = *src;
832 }
833 }
834 }
835 assert((size_t)(p - buf.base()) == msg_size);
836 req->pack();
837 if (!s->session->sock->write(buf, msg_size)) {
838 return cli_network_error;
839 }
840 return cli_ok;
841 }
842
cli_batch_insert(int statement,cli_oid_t * oid)843 int cli_batch_insert(int statement, cli_oid_t* oid)
844 {
845 return cli_insert(statement, oid);
846 }
847
cli_insert(int statement,cli_oid_t * oid)848 int cli_insert(int statement, cli_oid_t* oid)
849 {
850 int rc = cli_send_columns(statement, cli_cmd_insert);
851 if (rc == cli_ok) {
852 char buf[sizeof(cli_oid_t) + 8];
853 statement_desc* s = statements.get(statement);
854 if (!s->session->sock->read(buf, sizeof buf)) {
855 rc = cli_network_error;
856 } else {
857 rc = unpack4(buf);
858 s->prepared = true;
859 s->oid = unpack_oid(buf + 8);
860 if (oid != NULL) {
861 *oid = s->oid;
862 }
863 if (s->autoincrement) {
864 int4 rowid = unpack4(buf + 4);
865 for (column_binding* cb = s->columns; cb != NULL; cb = cb->next) {
866 if (cb->var_type == cli_autoincrement) {
867 *(int4*)cb->var_ptr = rowid;
868 }
869 }
870 }
871 }
872 }
873 return rc;
874 }
875
cli_update(int statement)876 int cli_update(int statement)
877 {
878 int rc = cli_send_columns(statement, cli_cmd_update);
879 if (rc == cli_ok) {
880 int4 response;
881 statement_desc* s = statements.get(statement);
882 s->updated = true;
883 if (!s->session->sock->read(&response, sizeof response)) {
884 rc = cli_network_error;
885 } else {
886 unpack4(response);
887 rc = response;
888 }
889 }
890 return rc;
891 }
892
cli_get(int statement,int cmd,cli_oid_t value=0)893 static int cli_get(int statement, int cmd, cli_oid_t value = 0)
894 {
895 statement_desc* s = statements.get(statement);
896 if (s == NULL) {
897 return cli_bad_descriptor;
898 }
899 if (!s->prepared) {
900 return cli_not_fetched;
901 }
902 struct get_req {
903 cli_request req;
904 cli_oid_t value;
905 } get;
906 int length = sizeof(cli_request);
907 if (cmd == cli_cmd_skip) {
908 length += 4;
909 pack4((char*)(&get.req+1), (int)value);
910 } else if (cmd == cli_cmd_seek) {
911 length += sizeof(cli_oid_t);
912 pack_oid((char*)(&get.req+1), value);
913 }
914 get.req.length = length;
915 get.req.cmd = cmd;
916 get.req.stmt_id = statement;
917 get.req.pack();
918 if (!s->session->sock->write(&get.req, length)) {
919 return cli_network_error;
920 }
921 int4 response;
922 if (!s->session->sock->read(&response, sizeof response)) {
923 return cli_network_error;
924 }
925 unpack4(response);
926 if (response <= 0) {
927 return response;
928 }
929 if (s->buf_size < (size_t)response-4) {
930 delete[] s->buf;
931 s->buf_size = response-4 < DEFAULT_BUF_SIZE ? DEFAULT_BUF_SIZE : response-4;
932 s->buf = new char[s->buf_size];
933 }
934 char* buf = s->buf;
935 if (!s->session->sock->read(buf, response-4)) {
936 return cli_network_error;
937 }
938 char* p = buf;
939 int result = cli_ok;
940 if (cmd == cli_cmd_seek) {
941 s->oid = value;
942 } else {
943 s->oid = unpack_oid(p);
944 if (s->oid == 0) {
945 return cli_not_found;
946 }
947 }
948 p += sizeof(cli_oid_t);
949 for (column_binding* cb = s->columns; cb != NULL; cb = cb->next) {
950 int type = *p++;
951 if (cb->var_type == cli_any) {
952 cb->var_type = type;
953 } else {
954 assert(cb->var_type == type);
955 }
956 if (cb->set_fnc != NULL) {
957 int len = unpack4(p);
958 p += 4;
959 char* dst = (char*)cb->set_fnc(type, cb->var_ptr, len, cb->name, statement, p, cb->user_data);
960 if (dst == NULL) {
961 continue;
962 }
963 if (type == cli_array_of_string) {
964 char_t** s = (char_t**)dst;
965 #ifdef UNICODE
966 char_t* q = (char_t*)((size_t)p & ~(sizeof(char_t)-1));
967 while (--len >= 0) {
968 char* p1 = unpack_str(q, p);
969 *s++ = q;
970 q += (p1 - p) / sizeof(char_t);
971 p = p1;
972 }
973 #else
974 while (--len >= 0) {
975 *s++ = p;
976 p += strlen(p) + 1;
977 }
978 #endif
979 } else if (type >= cli_array_of_oid && type < cli_array_of_string) {
980 switch (sizeof_type[type-cli_array_of_oid]) {
981 case 2:
982 while (--len >= 0) {
983 p = unpack2(dst, p);
984 dst += 2;
985 }
986 break;
987 case 4:
988 while (--len >= 0) {
989 p = unpack4(dst, p);
990 dst += 4;
991 }
992 break;
993 case 8:
994 while (--len >= 0) {
995 p = unpack8(dst, p);
996 dst += 8;
997 }
998 break;
999 default:
1000 memcpy(dst, p, len);
1001 p += len;
1002 }
1003 #ifdef UNICODE
1004 } else if (type == cli_asciiz) {
1005 unpack_str((char_t*)dst, p);
1006 p += len*sizeof(char_t);
1007 #endif
1008 } else {
1009 memcpy(dst, p, len);
1010 p += len;
1011 }
1012 } else {
1013 if (type >= cli_asciiz && type <= cli_array_of_string) {
1014 int len = unpack4(p);
1015 p += 4;
1016 char* dst = (char*)cb->var_ptr;
1017 char* src = p;
1018 int n = len;
1019 if (cb->var_len != NULL) {
1020 if (n > *cb->var_len) {
1021 n = *cb->var_len;
1022 }
1023 *cb->var_len = len;
1024 }
1025 if (type >= cli_array_of_oid) {
1026 if (type == cli_array_of_string) {
1027 char_t** s = (char_t**)dst;
1028 len -= n;
1029 #ifdef UNICODE
1030 char_t* q = (char_t*)((size_t)p & ~(sizeof(char_t)-1));
1031 while (--n >= 0) {
1032 char* p1 = unpack_str(q, p);
1033 *s++ = q;
1034 q += (p1 - p) / sizeof(char_t);
1035 p = p1;
1036 }
1037 while (--len >= 0) {
1038 p = skip_str(p);
1039 }
1040 #else
1041 while (--n >= 0) {
1042 *s++ = p;
1043 p += strlen(p) + 1;
1044 }
1045 while (--len >= 0) {
1046 p += strlen(p) + 1;
1047 }
1048 #endif
1049 } else {
1050 switch (sizeof_type[type-cli_array_of_oid]) {
1051 case 2:
1052 while (--n >= 0) {
1053 src = unpack2(dst, src);
1054 dst += 2;
1055 }
1056 p += len*2;
1057 break;
1058 case 4:
1059 while (--n >= 0) {
1060 src = unpack4(dst, src);
1061 dst += 4;
1062 }
1063 p += len*4;
1064 break;
1065 case 8:
1066 while (--n >= 0) {
1067 src = unpack8(dst, src);
1068 dst += 8;
1069 }
1070 p += len*8;
1071 break;
1072 default:
1073 memcpy(dst, p, n);
1074 p += len;
1075 }
1076 }
1077 } else {
1078 switch (type) {
1079 case cli_pasciiz:
1080 dst = *(char**)dst;
1081 // no break
1082 case cli_asciiz:
1083 unpack_str((char_t*)dst, p, n);
1084 break;
1085 case cli_cstring:
1086 ((cli_cstring_t*)dst)->len = n;
1087 #ifdef UNICODE
1088 ((cli_cstring_t*)dst)->ptr = (char_t*)((size_t)p & ~(sizeof(char_t)-1));
1089 unpack_str(((cli_cstring_t*)dst)->ptr, p, n);
1090 #else
1091 ((cli_cstring_t*)dst)->ptr = p;
1092 #endif
1093 }
1094 p += len*sizeof(char_t);
1095 }
1096 } else if (type == cli_rectangle) {
1097 p = unpack_rectangle((cli_rectangle_t*)cb->var_ptr, p);
1098 } else {
1099 switch (sizeof_type[type]) {
1100 case 2:
1101 p = unpack2((char*)cb->var_ptr, p);
1102 break;
1103 case 4:
1104 p = unpack4((char*)cb->var_ptr, p);
1105 break;
1106 case 8:
1107 p = unpack8((char*)cb->var_ptr, p);
1108 break;
1109 default:
1110 *(char*)cb->var_ptr = *p++;
1111 }
1112 }
1113 }
1114 }
1115 s->updated = false;
1116 return result;
1117 }
1118
cli_get_first(int statement)1119 int cli_get_first(int statement)
1120 {
1121 return cli_get(statement, cli_cmd_get_first);
1122 }
1123
cli_get_last(int statement)1124 int cli_get_last(int statement)
1125 {
1126 return cli_get(statement, cli_cmd_get_last);
1127 }
1128
cli_get_next(int statement)1129 int cli_get_next(int statement)
1130 {
1131 return cli_get(statement, cli_cmd_get_next);
1132 }
1133
cli_get_prev(int statement)1134 int cli_get_prev(int statement)
1135 {
1136 return cli_get(statement, cli_cmd_get_prev);
1137 }
1138
cli_skip(int statement,int n)1139 int cli_skip(int statement, int n)
1140 {
1141 return cli_get(statement, cli_cmd_skip, n);
1142 }
1143
cli_seek(int statement,cli_oid_t oid)1144 int cli_seek(int statement, cli_oid_t oid)
1145 {
1146 return cli_get(statement, cli_cmd_seek, oid);
1147 }
1148
send_receive(int statement,int cmd)1149 static int send_receive(int statement, int cmd)
1150 {
1151 statement_desc* s = statements.get(statement);
1152 if (s == NULL) {
1153 return cli_bad_descriptor;
1154 }
1155 if (!s->prepared) {
1156 return cli_not_fetched;
1157 }
1158 cli_request req;
1159 req.length = sizeof(req);
1160 req.cmd = cmd;
1161 req.stmt_id = statement;
1162 req.pack();
1163 int4 response = cli_ok;
1164 if (!s->session->sock->write(&req, sizeof req)) {
1165 return cli_network_error;
1166 }
1167 if (!s->session->sock->read(&response, sizeof response)) {
1168 return cli_network_error;
1169 }
1170 unpack4(response);
1171 return response;
1172 }
1173
cli_freeze(int statement)1174 int cli_freeze(int statement)
1175 {
1176 return send_receive(statement, cli_cmd_freeze);
1177 }
1178
cli_unfreeze(int statement)1179 int cli_unfreeze(int statement)
1180 {
1181 return send_receive(statement, cli_cmd_unfreeze);
1182 }
1183
1184
cli_get_oid(int statement)1185 cli_oid_t cli_get_oid(int statement)
1186 {
1187 statement_desc* s = statements.get(statement);
1188 if (s == NULL) {
1189 return 0;
1190 }
1191 return s->oid;
1192 }
1193
1194
cli_send_command(int session,int statement,int cmd)1195 static int cli_send_command(int session, int statement, int cmd)
1196 {
1197 session_desc* s = sessions.get(session);
1198 if (s == NULL) {
1199 return cli_bad_descriptor;
1200 }
1201 cli_request req;
1202 req.length = sizeof(cli_request);
1203 req.cmd = cmd;
1204 req.stmt_id = statement;
1205 req.pack();
1206 if (!s->sock->write(&req, sizeof req)) {
1207 return cli_network_error;
1208 }
1209 int4 response;
1210 if (!s->sock->read(&response, sizeof response)) {
1211 return cli_network_error;
1212 }
1213 unpack4(response);
1214 return response;
1215 }
1216
cli_close_cursor(int statement)1217 int cli_close_cursor(int statement)
1218 {
1219 return cli_ok;
1220 }
1221
cli_free(int statement)1222 int cli_free(int statement)
1223 {
1224 statement_desc* stmt = statements.get(statement);
1225 session_desc* s = stmt->session;
1226 if (s == NULL) {
1227 return cli_bad_descriptor;
1228 }
1229 statement_desc *sp, **spp = &s->stmts;
1230 while ((sp = *spp) != stmt) {
1231 if (sp == NULL) {
1232 return cli_bad_descriptor;
1233 }
1234 spp = &sp->next;
1235 }
1236 *spp = stmt->next;
1237 stmt->free();
1238 statements.free(stmt);
1239 cli_request req;
1240 req.length = sizeof(cli_request);
1241 req.cmd = cli_cmd_free_statement;
1242 req.stmt_id = statement;
1243 req.pack();
1244 if (!s->sock->write(&req, sizeof req)) {
1245 return cli_network_error;
1246 }
1247 return cli_ok;
1248 }
1249
cli_exec_batch(int session)1250 int cli_exec_batch(int session)
1251 {
1252 return cli_ok;
1253 }
1254
cli_commit(int session)1255 int cli_commit(int session)
1256 {
1257 return cli_send_command(session, 0, cli_cmd_commit);
1258 }
1259
cli_precommit(int session)1260 int cli_precommit(int session)
1261 {
1262 return cli_send_command(session, 0, cli_cmd_precommit);
1263 }
1264
cli_abort(int session)1265 int cli_abort(int session)
1266 {
1267 return cli_send_command(session, 0, cli_cmd_abort);
1268 }
1269
cli_remove(int statement)1270 int cli_remove(int statement)
1271 {
1272 statement_desc* s = statements.get(statement);
1273 if (s == NULL) {
1274 return cli_bad_descriptor;
1275 }
1276 if (s->cursor_type != cli_cursor_for_update) {
1277 return cli_not_update_mode;
1278 }
1279 return cli_send_command(s->session->id, s->id, cli_cmd_remove);
1280 }
1281
cli_remove_current(int statement)1282 int cli_remove_current(int statement)
1283 {
1284 statement_desc* s = statements.get(statement);
1285 if (s == NULL) {
1286 return cli_bad_descriptor;
1287 }
1288 if (s->oid == 0) {
1289 return cli_not_found;
1290 }
1291 if (s->cursor_type != cli_cursor_for_update) {
1292 return cli_not_update_mode;
1293 }
1294 return cli_send_command(s->session->id, s->id, cli_cmd_remove_current);
1295 }
1296
1297
cli_describe(int session,char_t const * table,cli_field_descriptor ** fields)1298 int cli_describe(int session, char_t const* table, cli_field_descriptor** fields)
1299 {
1300 int len = (int)(sizeof(cli_request) + (STRLEN(table)+1)*sizeof(char_t));
1301 dbSmallBuffer<char> buf(len);
1302 cli_request* req = (cli_request*)buf.base();
1303 req->length = len;
1304 req->cmd = cli_cmd_describe_table;
1305 req->stmt_id = 0;
1306 pack_str((char*)(req+1), table);
1307 session_desc* s = sessions.get(session);
1308 if (s == NULL) {
1309 return cli_bad_descriptor;
1310 }
1311 req->pack();
1312 if (!s->sock->write(buf, len)) {
1313 return cli_network_error;
1314 }
1315 int4 response[2];
1316 if (!s->sock->read(response, sizeof response)) {
1317 return cli_network_error;
1318 }
1319 unpack4(response[0]);
1320 unpack4(response[1]);
1321 len = response[0];
1322 int nFields = response[1];
1323 if (nFields == -1) {
1324 return cli_table_not_found;
1325 }
1326 char* p = (char*)malloc(nFields*sizeof(cli_field_descriptor) + len);
1327 cli_field_descriptor* fp = (cli_field_descriptor*)p;
1328 p += nFields*sizeof(cli_field_descriptor);
1329 if (!s->sock->read(p, len)) {
1330 return cli_network_error;
1331 }
1332 *fields = fp;
1333 for (int i = nFields; --i >= 0; fp++) {
1334 fp->type = (enum cli_var_type)*p++;
1335 fp->flags = *p++ & 0xFF;
1336 fp->name = (char_t*)p;
1337 p = unpack_str((char_t*)fp->name, p);
1338 if (*(char_t*)p != 0) {
1339 fp->refTableName = (char_t*)p;
1340 p = unpack_str((char_t*)fp->refTableName, p);
1341 } else {
1342 p += sizeof(char_t);
1343 fp->refTableName = NULL;
1344 }
1345 if (*(char_t*)p != 0) {
1346 fp->inverseRefFieldName = (char_t*)p;
1347 p = unpack_str((char_t*)fp->inverseRefFieldName, p);
1348 } else {
1349 p += sizeof(char_t);
1350 fp->inverseRefFieldName = NULL;
1351 }
1352 }
1353 return nFields;
1354 }
1355
cli_describe_layout(int session,char_t const * table,cli_field_layout ** fields,int * rec_size)1356 int cli_describe_layout(int session, char_t const* table, cli_field_layout** fields, int* rec_size)
1357 {
1358 return cli_not_implemented;
1359 }
1360
1361
cli_show_tables(int session,cli_table_descriptor ** tables)1362 int cli_show_tables(int session, cli_table_descriptor** tables)
1363 {
1364 session_desc* s = sessions.get(session);
1365 if (s == NULL) {
1366 return cli_bad_descriptor;
1367 }
1368 cli_request req;
1369 req.length = sizeof(cli_request);
1370 req.cmd = cli_cmd_show_tables;
1371 req.stmt_id = 0;
1372 req.pack();
1373 if (!s->sock->write(&req, sizeof req)) {
1374 return cli_network_error;
1375 }
1376 int4 response[2];
1377 if (!s->sock->read(response, sizeof response)) {
1378 return cli_network_error;
1379 }
1380 unpack4(response[0]);
1381 unpack4(response[1]);
1382 int len = response[0];
1383 int nTables = response[1];
1384 if (nTables == -1) {
1385 return cli_table_not_found;
1386 }
1387 char* p = (char*)malloc(nTables*sizeof(cli_table_descriptor) + len);
1388 cli_table_descriptor* fp = (cli_table_descriptor*)p;
1389 p += nTables*sizeof(cli_table_descriptor);
1390 if (!s->sock->read(p, len)) {
1391 free(p);
1392 return cli_network_error;
1393 }
1394 *tables = fp;
1395 for (int i = nTables; --i >= 0; fp++) {
1396 fp->name = (char_t*)p;
1397 p += (STRLEN((char_t*)p)+1)*sizeof(char_t);
1398 }
1399 return nTables;
1400 }
1401
1402
cli_create(char_t const * databasePath,unsigned transactionCommitDelay,int openAttr,size_t poolSize)1403 int cli_create(char_t const* databasePath,
1404 unsigned transactionCommitDelay,
1405 int openAttr,
1406 size_t poolSize)
1407 {
1408 return cli_bad_address;
1409 }
1410
1411
cli_update_table(int cmd,int session,char_t const * tableName,int nColumns,cli_field_descriptor * columns)1412 static int cli_update_table(int cmd, int session, char_t const* tableName, int nColumns,
1413 cli_field_descriptor* columns)
1414 {
1415 int i;
1416 session_desc* s = sessions.get(session);
1417 if (s == NULL) {
1418 return cli_bad_descriptor;
1419 }
1420 size_t size = sizeof(cli_request) + 4 + (STRLEN(tableName)+1)*sizeof(char_t);
1421 for (i = 0; i < nColumns; i++) {
1422 size += 2 + (STRLEN(columns[i].name)+3)*sizeof(char_t);
1423 if (columns[i].refTableName != NULL) {
1424 size += STRLEN(columns[i].refTableName)*sizeof(char_t);
1425 }
1426 if (columns[i].inverseRefFieldName != NULL) {
1427 size += STRLEN(columns[i].inverseRefFieldName)*sizeof(char_t);
1428 }
1429 }
1430 dbSmallBuffer<char> buf(size);
1431 cli_request* req = (cli_request*)buf.base();
1432 req->length = (int4)size;
1433 req->cmd = cmd;
1434 req->stmt_id = 0;
1435 char* dst = (char*)(req + 1);
1436 dst = pack_str(dst, tableName);
1437 *dst++ = (char)nColumns;
1438 for (i = 0; i < nColumns; i++) {
1439 *dst++ = (char)columns[i].type;
1440 *dst++ = (char)columns[i].flags;
1441 dst = pack_str(dst, columns[i].name);
1442 if (columns[i].refTableName != NULL) {
1443 dst = pack_str(dst, columns[i].refTableName);
1444 } else {
1445 *(char_t*)dst = 0;
1446 dst += sizeof(char_t);
1447 }
1448 if (columns[i].inverseRefFieldName != NULL) {
1449 dst = pack_str(dst, columns[i].inverseRefFieldName);
1450 } else {
1451 *(char_t*)dst = 0;
1452 dst += sizeof(char_t);
1453 }
1454 }
1455 req->pack();
1456 if (!s->sock->write(buf, size)) {
1457 return cli_network_error;
1458 }
1459 int4 response;
1460 if (!s->sock->read(&response, sizeof response)) {
1461 return cli_network_error;
1462 }
1463 unpack4(response);
1464 return response;
1465 }
1466
cli_create_table(int session,char_t const * tableName,int nColumns,cli_field_descriptor * columns)1467 int cli_create_table(int session, char_t const* tableName, int nColumns,
1468 cli_field_descriptor* columns)
1469 {
1470 return cli_update_table(cli_cmd_create_table, session, tableName, nColumns, columns);
1471 }
1472
cli_alter_table(int session,char_t const * tableName,int nColumns,cli_field_descriptor * columns)1473 int cli_alter_table(int session, char_t const* tableName, int nColumns,
1474 cli_field_descriptor* columns)
1475 {
1476 return cli_update_table(cli_cmd_alter_table, session, tableName, nColumns, columns);
1477 }
1478
cli_drop_table(int session,char_t const * tableName)1479 int cli_drop_table(int session, char_t const* tableName)
1480 {
1481 session_desc* s = sessions.get(session);
1482 if (s == NULL) {
1483 return cli_bad_descriptor;
1484 }
1485 size_t size = sizeof(cli_request) + (STRLEN(tableName)+1)*sizeof(char_t);
1486 dbSmallBuffer<char> buf(size);
1487 cli_request* req = (cli_request*)buf.base();
1488 req->length = (int4)size;
1489 req->cmd = cli_cmd_drop_table;
1490 req->stmt_id = 0;
1491 pack_str((char*)(req + 1), tableName);
1492 req->pack();
1493 if (!s->sock->write(buf, size)) {
1494 return cli_network_error;
1495 }
1496 int4 response;
1497 if (!s->sock->read(&response, sizeof response)) {
1498 return cli_network_error;
1499 }
1500 unpack4(response);
1501 return response;
1502 }
1503
cli_alter_index(int session,char_t const * tableName,char_t const * fieldName,int newFlags)1504 int cli_alter_index(int session, char_t const* tableName, char_t const* fieldName, int newFlags)
1505 {
1506 session_desc* s = sessions.get(session);
1507 if (s == NULL) {
1508 return cli_bad_descriptor;
1509 }
1510 size_t size = sizeof(cli_request) + 1 + (STRLEN(tableName)+STRLEN(fieldName)+2)*sizeof(char_t);
1511 dbSmallBuffer<char> buf(size);
1512 cli_request* req = (cli_request*)buf.base();
1513 req->length = (int4)size;
1514 req->cmd = cli_cmd_alter_index;
1515 req->stmt_id = 0;
1516 char* dst = (char*)(req + 1);
1517 dst = pack_str(dst, tableName);
1518 dst = pack_str(dst, fieldName);
1519 *dst++ = newFlags;
1520 req->pack();
1521 if (!s->sock->write(buf, size)) {
1522 return cli_network_error;
1523 }
1524 int4 response;
1525 if (!s->sock->read(&response, sizeof response)) {
1526 return cli_network_error;
1527 }
1528 unpack4(response);
1529 return response;
1530 }
1531
1532
cli_set_error_handler(int session,cli_error_handler new_handler,void * context)1533 cli_error_handler cli_set_error_handler(int session, cli_error_handler new_handler, void* context)
1534 {
1535 return NULL;
1536 }
1537
cli_attach(int session)1538 int cli_attach(int session)
1539 {
1540 return cli_not_implemented;
1541 }
1542
cli_detach(int session,int detach_mode)1543 int cli_detach(int session, int detach_mode)
1544 {
1545 return cli_not_implemented;
1546 }
1547
cli_lock(int session)1548 int cli_lock(int session)
1549 {
1550 session_desc* s = sessions.get(session);
1551 if (s == NULL) {
1552 return cli_bad_descriptor;
1553 }
1554 cli_request req;
1555 req.length = sizeof(req);
1556 req.cmd = cli_cmd_lock;
1557 req.stmt_id = 0;
1558 req.pack();
1559 return s->sock->write(&req, sizeof req) ? cli_ok : cli_network_error;
1560 }
1561
cli_free_memory(int,void * ptr)1562 void cli_free_memory(int, void* ptr)
1563 {
1564 free(ptr);
1565 }
1566
cli_set_trace_function(cli_trace_function_t)1567 void cli_set_trace_function(cli_trace_function_t)
1568 {
1569 }
1570
cli_prepare_query(int session,char const * query)1571 int cli_prepare_query(int session, char const* query)
1572 {
1573 return cli_not_implemented;
1574 }
1575
cli_execute_query(int statement,int for_update,void * record_struct,...)1576 int cli_execute_query(int statement, int for_update, void* record_struct, ...)
1577 {
1578 return cli_not_implemented;
1579 }
1580
cli_execute_query_ex(int statement,int for_update,void * record_struct,int n_params,int * param_types,void ** param_value)1581 int cli_execute_query_ex(int statement, int for_update, void* record_struct, int n_params, int* param_types, void** param_value)
1582 {
1583 return cli_not_implemented;
1584 }
1585
cli_insert_struct(int session,char_t const * table_name,void * record_struct,cli_oid_t * oid)1586 int cli_insert_struct(int session, char_t const* table_name, void* record_struct, cli_oid_t* oid)
1587 {
1588 return cli_not_implemented;
1589 }
1590
cli_get_field_size(cli_field_descriptor * fields,int field_no)1591 int cli_get_field_size(cli_field_descriptor* fields, int field_no)
1592 {
1593 return sizeof_type[fields[field_no].type];
1594 }
1595
1596
cli_get_field_offset(cli_field_descriptor * fields,int field_no)1597 int cli_get_field_offset(cli_field_descriptor* fields, int field_no)
1598 {
1599 int offs = 0;
1600 int size = 0;
1601 for (int i = 0; i <= field_no; i++) {
1602 size = sizeof_type[fields[i].type];
1603 offs = DOALIGN(offs, alignof_type[fields[i].type]);
1604 offs += size;
1605 }
1606 return offs - size;
1607 }
1608
cli_xml_export(int session,FILE * out,char_t const * const * tables,int n_tables,cli_export_method method)1609 int cli_xml_export(int session, FILE* out, char_t const* const* tables, int n_tables, cli_export_method method)
1610 {
1611 return cli_not_implemented;
1612 }
1613
cli_xml_import(int session,FILE * in)1614 int cli_xml_import(int session, FILE* in)
1615 {
1616 return cli_not_implemented;
1617 }
1618
cli_backup(int session,char_t const * file_name,int compactify)1619 int cli_backup(int session, char_t const* file_name, int compactify)
1620 {
1621 return cli_not_implemented;
1622 }
1623
cli_schedule_backup(int session,char_t const * file_name,int period)1624 int cli_schedule_backup(int session, char_t const* file_name, int period)
1625 {
1626 return cli_not_implemented;
1627 }
1628
cli_get_database_size(int session,cli_nat8_t * size)1629 int cli_get_database_size(int session, cli_nat8_t* size)
1630 {
1631 return cli_not_implemented;
1632 }
1633
cli_get_wrapping_rectangle(int session,char_t const * table,char_t const * field,cli_rectangle_t * rect)1634 int cli_get_wrapping_rectangle(int session, char_t const* table, char_t const* field, cli_rectangle_t* rect)
1635 {
1636 return cli_not_implemented;
1637 }
1638