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