ecere/gui/Window: Fixed lock-up closing code editor while Finding in Files on Unix
[sdk] / eda / drivers / MySQL.ec
1 import "ecere"
2 import "eda"
3
4 define MySQL = "MySQL";
5
6 #ifdef COMMENTED_OUT_MYSQL_NEED_MATCH_MODIFIED_DRIVER_STRUCTURE
7
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include <mysql.h>
11 #define DEFALT_SQL_STMT "SELECT * FROM db"
12
13 static MySqlLib mySqlLib;
14
15 static void LogMySqlError(MYSQL * mySql, String msg)
16 {
17    Logf("%s\n   MySql Error: #%d %s\n", msg, mysql_errno(mySql), mysql_error(mySql));
18 }
19
20 static void LogMySqlErrorf(MYSQL * mySql, String format, ...)
21 {
22    char msg[MAX_F_STRING];
23
24    va_list args;
25    va_start(args, format);
26    vsprintf(msg, format, args);
27    va_end(args);
28
29    Logf("%s\n   MySql Error: #%d %s\n", msg, mysql_errno(mySql), mysql_error(mySql));
30 }
31
32 static class MySqlLib
33 {
34    MySqlLib()
35    {
36       mysql_library_init(0, null, null);
37    }
38
39    ~MySqlLib()
40    {
41       mysql_library_end();
42    }
43 }
44
45 static class MySqlDataSource : struct
46 {
47 public:
48    MYSQL * mySql;
49 }
50
51 static class MySqlDatabase : struct
52 {
53 public:
54    MYSQL * mySql;
55
56    MySqlDataSource src;
57 }
58
59 static class MySqlTable : struct
60 {
61 public:
62    MYSQL * mySql;
63    MYSQL_RES * myRes;
64
65    MySqlDatabase dDb;
66    MySqlField dFld;
67    MySqlRow dRow;
68
69    Field fld;
70    Row row;
71 }
72
73 static class MySqlField : struct
74 {
75 public:
76    MYSQL_FIELD * myFlds;
77
78    MySqlTable dTbl;
79
80    uint fldsCount;
81    uint fldsPos;
82 }
83
84 static class MySqlRow : struct
85 {
86 public:
87    MYSQL_ROW myRow;
88    unsigned long *myLengths;
89
90    MySqlTable dTbl;
91    MySqlField dFld;
92
93    Field fld;
94
95    uint rowsCount;
96    uint rowsPos;
97 }
98
99 class MySqlDataDriver : DataDriver
100 {
101 public:
102
103    class_property(name) = "MySql";
104
105    /* -------------------------------------------------------------------------------------------------- */
106    /* --- Driver --------------------------------------------------------------------------------------- */
107
108    uint ::DriverDefaultPort()
109    {
110       return MYSQL_PORT;
111    }
112
113    /* -------------------------------------------------------------------------------------------------- */
114    /* --- Data Source ---------------------------------------------------------------------------------- */
115
116    void ::SourceClose(DataSource ds)
117    {
118       MySqlDataSource src = (MySqlDataSource)ds.driverData;
119       if(src)
120       {
121          if(src.mySql) mysql_close(src.mySql);
122          delete src;
123          ds.driverData = null;
124       }
125    }
126
127    void ::SourceStatus(DataSource ds)
128    {
129       MySqlDataSource src = (MySqlDataSource)ds.driverData;
130       const String pszT;
131       Log(" ********************************************* \n");
132       Log(" *      MySql Status Info                    * \n");
133       Log(" ********************************************* \n");
134          pszT = mysql_get_client_info(); Logf("   Client info: %s\n", pszT);
135          pszT = mysql_get_host_info(src.mySql); Logf("   Host info: %s\n", pszT);
136          pszT = mysql_get_server_info(src.mySql); Logf("   Server info: %s\n", pszT);
137       Log("     _____________________________________\n\n");
138
139       Log(" ********************************************* \n");
140       Log(" *      Stats                                * \n");
141       Log(" ********************************************* \n");
142          pszT = mysql_stat(src.mySql); Logf("   %s\n", pszT);
143       Log("     _____________________________________\n\n");
144    }
145
146    bool ::SourceConnect(DataSource ds, const String host, const String user, const String password, uint port)
147    {
148       bool success = false;
149       MySqlDataSource src {};
150       if(!mySqlLib) mySqlLib = { };
151       if(src.mySql) mysql_close(src.mySql);
152       if(src.mySql = mysql_init((MYSQL *) 0))
153       {
154          if(mysql_real_connect(src.mySql, host, user, password, null, port, null, 0))
155          {
156             src.mySql->reconnect = 1;
157             success = true;
158          }
159          else
160          {
161             LogMySqlErrorf(src.mySql, "Can't connect to the mysql server on port %d !\n", port);
162             mysql_close(src.mySql);
163          }
164       }
165       else
166       {
167          LogMySqlError(src.mySql, "Can't initialize mysql socket");
168          mysql_close(src.mySql);
169       }
170       ds.driverData = (void *)src;
171       return success;
172    }
173
174    uint ::SourceDatabasesCount(DataSource ds)
175    {
176       MySqlDataSource src = (MySqlDataSource)ds.driverData;
177       Log("TODO: MySql - DataSourceDatabasesCount");
178       return 0;
179    }
180
181    /* -------------------------------------------------------------------------------------------------- */
182    /* --- Database ------------------------------------------------------------------------------------- */
183
184    void ::DatabaseClose(Database db)
185    {
186       MySqlDatabase dDb = (MySqlDatabase)db.driverData;
187       Log("TODO: MySql - DatabaseClose");
188    }
189
190    uint ::DatabaseTablesCount(Database db)
191    {
192       MySqlDatabase dDb = (MySqlDatabase)db.driverData;
193       Log("TODO: MySql - DatabaseTablesCount");
194       return 0;
195    }
196
197    uint ::DatabaseViewsCount(Database db)
198    {
199       MySqlDatabase dDb = (MySqlDatabase)db.driverData;
200       Log("TODO: MySql - DatabaseViewsCount");
201       return 0;
202    }
203
204    String ::DatabaseNameGet(Database db)
205    {
206       MySqlDatabase dDb = (MySqlDatabase)db.driverData;
207       Log("TODO: MySql - DatabaseNameGet");
208       return null;
209    }
210
211    bool ::DatabaseNameSet(Database db, const String value)
212    {
213       MySqlDatabase dDb = (MySqlDatabase)db.driverData;
214       Log("TODO: MySql - DatabaseNameSet");
215       return false;
216    }
217
218    bool ::DatabaseOpen(Database db, DataSource ds, const String name, OpenOptions options)
219    {
220       MySqlDataSource src = (MySqlDataSource)ds.driverData;
221       MySqlDatabase dDb { mySql = src.mySql, src = src };
222       Table databases;
223       db.driver = ds.driver;
224       db.driverData = (void *)dDb;
225
226       databases = ds.OpenTable(null, { databasesList });
227       if(databases)
228       {
229          if(databases.row.field.Seek("SCHEMA_NAME", firstEqual))
230          {
231             if(!databases.row.Seek(name, firstEqual))
232             {
233                if(options.create == create)
234                {
235                   char ddl[MAX_F_STRING];
236                   sprintf(ddl, "CREATE DATABASE IF NOT EXISTS %s", name);  //  [[DEFAULT] CHARACTER SET, [[DEFAULT] COLLATE]]
237                   if(mysql_query(src.mySql, ddl))
238                      LogMySqlErrorf(src.mySql, "Couldn't execute DDL statement on the server!\n   %s", ddl);
239                }
240                else
241                {
242                   Logf("Database (%s) does not exist.\n", name);
243                   return false;
244                }
245             }
246          }
247          else
248             Log("Unable to detect if database exists!\n");
249          databases.Close();
250       }
251       else
252          Log("Unable to detect if database exists!\n");
253
254       if(mysql_select_db(dDb.mySql, name) < 0)
255       {
256          LogMySqlErrorf(src.mySql, "Can't open the %s database!\n", db);
257          return false;
258       }
259       return true;
260    }
261
262    bool ::DatabaseDelete(Database db, DataSource ds, const String name)
263    {
264       if(db)
265       {
266          MySqlDatabase dDb = (MySqlDatabase)db.driverData;
267       }
268       else
269       {
270          MySqlDataSource src = (MySqlDataSource)ds.driverData;
271       }
272       Log("TODO: MySql - DatabaseDelete");
273       return false;
274    }
275
276    /* -------------------------------------------------------------------------------------------------- */
277    /* --- Table ---------------------------------------------------------------------------------------- */
278
279    void ::TableClose(Table tbl)
280    {
281       MySqlTable dTbl = (MySqlTable)tbl.driverData;
282       if(dTbl.myRes) mysql_free_result(dTbl.myRes);
283    }
284
285    uint ::TableFieldsCount(Table tbl)
286    {
287       MySqlTable dTbl = (MySqlTable)tbl.driverData;
288       return mysql_num_fields(dTbl.myRes);
289    }
290
291    uint ::TableRowsCount(Table tbl)
292    {
293       MySqlTable dTbl = (MySqlTable)tbl.driverData;
294       return (uint)mysql_num_rows(dTbl.myRes);
295    }
296
297    Field ::TableField(Table tbl)
298    {
299       MySqlTable dTbl = (MySqlTable)tbl.driverData;
300       if(!dTbl.fld)
301       {
302          dTbl.dFld = MySqlField { mysql_fetch_fields(dTbl.myRes), dTbl = dTbl, fldsCount = mysql_num_fields(dTbl.myRes), fldsPos = -1 };
303          dTbl.fld = Field { driver = tbl.driver, driverData = dTbl.dFld };
304       }
305       return dTbl.fld;
306    }
307
308    Row ::TableRow(Table tbl)
309    {
310       MySqlTable dTbl = (MySqlTable)tbl.driverData;
311       if(!dTbl.row)
312       {
313          dTbl.dRow = MySqlRow { dTbl = dTbl, rowsCount = (uint)mysql_num_rows(dTbl.myRes), rowsPos = -1 };
314          dTbl.row = Row { driver = tbl.driver, driverData = dTbl.dRow };
315       }
316       return dTbl.row;
317    }
318
319    String ::TableNameGet(Table tbl)
320    {
321       MySqlTable dTbl = (MySqlTable)tbl.driverData;
322       Log("TODO: MySql - TableNameGet");
323       return null;
324    }
325
326    bool ::TableNameSet(Table tbl, const String value)
327    {
328       MySqlTable dTbl = (MySqlTable)tbl.driverData;
329       Log("TODO: MySql - TableNameSet");
330       return false;
331    }
332
333    bool ::TableOpen(Table tbl, Database db, DataSource ds, const String query, OpenOptions options)
334    {
335       char sql[MAX_F_STRING];
336       MySqlDataSource src;
337       MySqlDatabase dDb;
338       MySqlTable dTbl { };
339       Table tables;
340       tbl.driverData = (void *)dTbl;
341       if(db)
342       {
343          dDb = (MySqlDatabase)db.driverData;
344          src = dDb.src;
345          dTbl.mySql = dDb.mySql;
346          tbl.driver = db.driver;
347          if(options.type == tableRows)
348             tables = db.OpenTable(null, { tablesList });
349          else if(options.type == viewRows)
350             ;
351       }
352       else
353       {
354          src = (MySqlDataSource)ds.driverData;
355          dTbl.mySql = src.mySql;
356          tbl.driver = ds.driver;
357          if(options.type == tableRows)
358             tables = ds.OpenTable(null, { tablesList });
359          else if(options.type == viewRows)
360             ;
361       }
362
363       if(options.type == tableRows)
364       {
365          if(tables)
366          {
367             if(tables.row.field.Seek("TABLE_NAME", firstEqual))
368             {
369                if(!tables.row.Seek(query, firstEqual))
370                {
371                   if(options.create == create)
372                   {
373                      char ddl[MAX_F_STRING];
374                      sprintf(ddl, "CREATE TABLE IF NOT EXISTS %s (a INT);", query);
375                      if(mysql_query(src.mySql, ddl))
376                         LogMySqlErrorf(src.mySql, "Couldn't execute DDL statement on the server!\n   %s", ddl);
377                   }
378                   else
379                   {
380                      Logf("Table (%s) does not exist.\n", query);
381                      return false;
382                   }
383                }
384             }
385             else
386                Log("Unable to detect if table exists!\n");
387             tables.Close();
388          }
389          else
390             Log("Unable to detect if table exists!\n");
391       }
392
393       switch(options.type)
394       {
395          case queryRows:
396             if(!mysql_query(dTbl.mySql, query))
397             {
398                if(options.access == integral)
399                   dTbl.myRes = mysql_store_result(dTbl.mySql);
400                else
401                   dTbl.myRes = mysql_use_result(dTbl.mySql);
402             }
403             else
404                LogMySqlErrorf(dTbl.mySql, "Couldn't execute %s on the server!", sql);
405             break;
406          case tableRows:
407             sprintf(sql, "SELECT * FROM %s", query);
408             if(!mysql_query(dTbl.mySql, sql))
409             {
410                if(options.access == integral)
411                   dTbl.myRes = mysql_store_result(dTbl.mySql);
412                else
413                   dTbl.myRes = mysql_use_result(dTbl.mySql);
414             }
415             else
416                LogMySqlErrorf(dTbl.mySql, "Couldn't execute %s on the server!", sql);
417             break;
418          case viewRows:
419             break;
420          case processesList:
421             dTbl.myRes = mysql_list_processes(dTbl.mySql);
422             break;
423          case databasesList:
424             dTbl.myRes = mysql_list_dbs(dTbl.mySql, null);
425             break;
426          case tablesList:
427             dTbl.myRes = mysql_list_tables(dTbl.mySql, null);
428             break;
429          case fieldsList:
430             sprintf(sql, "SHOW COLUMNS FROM %s", query);
431             if(!mysql_query(dTbl.mySql, sql))
432                dTbl.myRes = mysql_store_result(dTbl.mySql);
433             else
434                LogMySqlErrorf(dTbl.mySql, "Listing fields for table %s failed!", query);
435             break;
436       }
437
438       if(dTbl.myRes)
439       {
440          //dTbl.fldsCount = mysql_num_fields(dTbl.myRes);
441          //dTbl.flds = mysql_fetch_fields(dTbl.myRes);
442          //dTbl.fldsPos = 0;
443          return true;
444       }
445       return false;
446    }
447
448    bool ::TableDelete(Table tbl, Database db, const String name)
449    {
450       if(tbl)
451       {
452          MySqlTable dTbl = (MySqlTable)tbl.driverData;
453       }
454       else
455       {
456          MySqlDatabase dDb = (MySqlDatabase)db.driverData;
457       }
458       Log("TODO: MySql - TableDelete");
459       return false;
460    }
461
462    /* -------------------------------------------------------------------------------------------------- */
463    /* --- Field ---------------------------------------------------------------------------------------- */
464
465    bool FieldEnd(Field fld)
466    {
467       MySqlField dFld = (MySqlField)fld.driverData;
468       return dFld.fldsPos == dFld.fldsCount;
469    }
470
471    bool FieldNext(Field fld)
472    {
473       MySqlField dFld = (MySqlField)fld.driverData;
474       /*if(dFld.fldsPos == -1)
475          ;//dFld.fldsPos = 0;
476       */
477       if(dFld.fldsPos == dFld.fldsCount)
478          return false;
479       dFld.fldsPos++;
480       return true;
481    }
482
483    bool FieldPrevious(Field fld)
484    {
485       MySqlField dFld = (MySqlField)fld.driverData;
486       if(dFld.fldsPos == -1)
487          dFld.fldsPos = dFld.fldsCount ? dFld.fldsCount + 1 : 0;
488       else if(dFld.fldsPos == 0)
489       {
490          dFld.fldsPos = dFld.fldsCount;
491          return false;
492       }
493       dFld.fldsPos--;
494       return true;
495    }
496
497    bool FieldSeek(Field fld, String value, SeekOptions options)
498    {
499       MySqlField dFld = (MySqlField)fld.driverData;
500       if(options == reset)
501       {
502          if(dFld.fldsCount)
503          {
504             dFld.fldsPos = -1;
505             return true;
506          }
507       }
508       else if(options == first)
509       {
510          if(dFld.fldsCount)
511          {
512             dFld.fldsPos = 0;
513             return true;
514          }
515       }
516       else if(options == firstEqual)
517       {
518          int len = strlen(value);
519          for(dFld.fldsPos = 0; dFld.fldsPos < dFld.fldsCount; dFld.fldsPos++)
520             if(dFld.myFlds[dFld.fldsPos].org_name_length == len && !strncmp(dFld.myFlds[dFld.fldsPos].org_name, value, len))
521                break;
522          if(dFld.fldsPos == dFld.fldsCount)
523          {
524             dFld.fldsPos = -1;
525             return false;
526          }
527          return true;
528       }
529       else if(options == last)
530       {
531          if(dFld.fldsCount)
532          {
533             dFld.fldsPos = dFld.fldsCount - 1;
534             return true;
535          }
536       }
537       else if(options == none)
538       {
539          dFld.fldsPos = -1;
540          return false;
541       }
542       return false;
543    }
544
545    String ::FieldNameGet(Field fld)
546    {
547       MySqlField dFld = (MySqlField)fld.driverData;
548       String name = new char [dFld.myFlds[dFld.fldsPos].org_name_length + 1];
549       strncpy(name, dFld.myFlds[dFld.fldsPos].org_name, dFld.myFlds[dFld.fldsPos].org_name_length);
550       name[dFld.myFlds[dFld.fldsPos].org_name_length] = '\0';
551       return name;
552    }
553
554    bool ::FieldNameSet(Field fld, const String value)
555    {
556       MySqlField dFld = (MySqlField)fld.driverData;
557       Log("TODO: MySql - FieldNameSet");
558       return false;
559    }
560
561    /* -------------------------------------------------------------------------------------------------- */
562    /* --- Row ------------------------------------------------------------------------------------------ */
563
564    Field ::RowField(Row row)
565    {
566       MySqlRow dRow = (MySqlRow)row.driverData;
567       MySqlTable dTbl = dRow.dTbl;
568       if(!dRow.fld)
569       {
570          dRow.dFld = MySqlField { mysql_fetch_fields(dTbl.myRes), dTbl, mysql_num_fields(dTbl.myRes), -1 };
571          dRow.fld = Field { driver = row.driver, driverData = dRow.dFld };
572       }
573       return dRow.fld;
574    }
575
576    bool ::RowEnd(Row row)
577    {
578       MySqlRow dRow = (MySqlRow)row.driverData;
579       return dRow.rowsPos == dRow.rowsCount;
580    }
581
582    bool ::RowNext(Row row)
583    {
584       MySqlRow dRow = (MySqlRow)row.driverData;
585       MySqlTable dTbl = dRow.dTbl;
586       if(dRow.rowsPos == -1)
587          dRow.rowsPos = 0;
588       if(dRow.rowsPos == dRow.rowsCount)
589          return false;
590       dRow.rowsPos++;
591       dRow.myRow = mysql_fetch_row(dTbl.myRes);  // this won't work in all situations...
592       dRow.myLengths = mysql_fetch_lengths(dTbl.myRes);
593       return true;
594    }
595
596    bool ::RowPrevious(Row row)
597    {
598       MySqlRow dRow = (MySqlRow)row.driverData;
599       MySqlTable dTbl = dRow.dTbl;
600       if(dRow.rowsPos == -1)
601          dRow.rowsPos = dRow.rowsCount ? dRow.rowsCount + 1 : 0;
602       else if(dRow.rowsPos == 0)
603       {
604          dRow.rowsPos = dRow.rowsCount;
605          return false;
606       }
607       dRow.rowsPos--;
608       dRow.myRow = mysql_fetch_row(dTbl.myRes);  // this won't work at all...
609       Log("TODO: MySql - FieldNameSet");
610       return false;
611       return true;
612    }
613
614    bool ::RowSeek(Row row, const String value, SeekOptions options)
615    {
616       MySqlRow dRow = (MySqlRow)row.driverData;
617       if(options == first || options == reset)
618       {
619          if(dRow.rowsCount)
620          {
621             dRow.rowsPos = -1;
622             mysql_data_seek(dRow.dTbl.myRes, 0);
623             if(options == first)
624                row.Next(row);
625             return true;
626          }
627       }
628       else if(options == firstEqual)
629       {
630          dRow.rowsPos = -1;
631          mysql_data_seek(dRow.dTbl.myRes, 0);
632          while(row.Next(row))
633             if(!strcmp(row.stringValue, value))
634                return true;
635          return false;
636       }
637       /*else if(options == Last)
638       {
639          if(dFld.fldsCount)
640          {
641             dFld.fldsPos = dFld.fldsCount - 1;
642             return true;
643          }
644       }*/
645       /*else if(options == null)
646       {
647          dFld.fldsPos = -1;
648          return false;
649       }*/
650       //Log("TODO: MySql - RowSeek");
651       return false;
652    }
653
654    String ::RowStringValueGet(Row row)
655    {
656       char temp[4096];
657       MySqlRow dRow = (MySqlRow)row.driverData;
658       MySqlTable dTbl = dRow.dTbl;
659       MySqlField dFld = dRow.dFld;
660
661       switch(dFld.myFlds[dFld.fldsPos].type)
662       {
663          case FIELD_TYPE_TINY:
664          case FIELD_TYPE_SHORT:
665          case FIELD_TYPE_LONG:
666          case FIELD_TYPE_INT24:
667          case FIELD_TYPE_LONGLONG:
668          {
669             char temp[32];
670             sprintf(temp, "%d", dRow.myRow[dFld.fldsPos]);
671             return CopyString(temp);
672          }
673          case FIELD_TYPE_DECIMAL:
674             return CopyString("FIELD_TYPE_DECIMAL");
675          case FIELD_TYPE_FLOAT:
676             return CopyString("FIELD_TYPE_FLOAT");
677          case FIELD_TYPE_DOUBLE:
678             return CopyString("FIELD_TYPE_DOUBLE");
679          case FIELD_TYPE_TIMESTAMP:
680             return CopyString("FIELD_TYPE_TIMESTAMP");
681          case FIELD_TYPE_DATE:
682             return CopyString("FIELD_TYPE_DATE");
683          case FIELD_TYPE_TIME:
684             return CopyString("FIELD_TYPE_TIME");
685          case FIELD_TYPE_DATETIME:
686             return CopyString("FIELD_TYPE_DATETIME");
687          case FIELD_TYPE_YEAR:
688             return CopyString("FIELD_TYPE_YEAR");
689          case FIELD_TYPE_STRING:
690             return dRow.myRow[dFld.fldsPos];
691          case FIELD_TYPE_VAR_STRING:
692             return dRow.myRow[dFld.fldsPos];
693          case FIELD_TYPE_BLOB:
694             return CopyString("FIELD_TYPE_BLOB");
695          case FIELD_TYPE_SET:
696             return CopyString("FIELD_TYPE_SET");
697          case FIELD_TYPE_ENUM:
698             return CopyString("FIELD_TYPE_ENUM");
699          case FIELD_TYPE_NULL:
700             return CopyString("FIELD_TYPE_NULL");
701          //case FIELD_TYPE_CHAR:
702          //   return CopyString("FIELD_TYPE_CHAR");
703          default:
704             return CopyString("DEFAULT");
705       }
706       //sprintf(temp, "%.*s", (int)dRow.myLengths[dFld.fldsPos], dRow.myRow[dFld.fldsPos] ? dRow.myRow[dFld.fldsPos] : "null");
707       /*if(!dFld || dRow.myRow[dFld.fldsPos] == null || !strlen(dRow.myRow[dFld.fldsPos]))
708          return null;
709       return dRow.myRow[dFld.fldsPos];*/
710       //return CopyString(temp);
711    }
712
713    bool ::RowStringValueSet(Row row, const String value)
714    {
715       MySqlRow dRow = (MySqlRow)row.driverData;
716       Log("TODO: MySql - RowStringValueSet");
717       return false;
718    }
719
720 }
721
722 #endif