BASIC Developer & Support Resources > Scripting Languages

GNOME-DB

(1/10) > >>

JRS:
I was introduced to the GNOME-DB project when I added database access to the GNOME Planner. (project manger software) It's what ODBC is to Windows. I had asked Peter if he thought I could use his GTK-Server interpretive CALL interface with GNOME-DB. His response was NO because ScriptBasic couldn't pass a pointer to it's variables. Armando added a VARPTR() function to the gtk-server.so ScriptBasic extension module which is used with the SQLite3 demo post in the iCALL thread. I would like to initiate a ScriptBasic, BaCon and BCX code challenge to show the following C example running under each of the Basic offerings. This will give the users of each Basic a common interface to MySQL, SQLite and PostgreSQL (with support for data binding to Gtk widgets.)

GObject Introspection (GNOME script engine plug-in interface)

--- Quote ---It makes sense to build many kinds of applications using (at least) two different levels and languages. Those being C+GObject, and a managed (GC'd) runtime. C is good for graphics, multimedia, and lower level systems work. However, writing complex software is difficult and error-prone without garbage collection. A managed runtime such as Vala, JavaScript, Python, Java, Lua, .NET, Scheme etc. makes a lot of sense for non-fast-path application logic such as configuration, layout, dialogs, etc.

--- End quote ---


 


--- Code: ---#include <libgda.h>
#include <libgda-ui/libgda-ui.h>

int
main (int argc, char *argv[])
{
        gtk_init (&argc, &argv);
        gdaui_init ();

        /* create a login dialog window to let the user select a data source (or declare a new one)
         * and specify a username and password if necessary
         */
        GtkWidget *window, *login;
        window = gtk_dialog_new_with_buttons ("Select the Data Source to connect to",
                                              NULL,
                                              0,
                                              GTK_STOCK_CANCEL,
                                              GTK_RESPONSE_NONE,
                                              GTK_STOCK_OK,
                                              GTK_RESPONSE_OK,
                                              NULL);

        /* Create the login widget */
        login = gdaui_login_new (NULL);
        gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (window))),
                            login, TRUE, TRUE, 0);
        gtk_widget_show (login);

        if (gtk_dialog_run (GTK_DIALOG (window)) != GTK_RESPONSE_OK) {
                g_print ("Cancelled!\n");
                exit (0);
        }

        /* open the connection */
        const GdaDsnInfo *dsninfo;
        GdaConnection *cnc;
        GError *error;

        dsninfo = gdaui_login_get_connection_information (GDAUI_LOGIN (login));
        cnc = gda_connection_open_from_string (dsninfo->provider,
                                               dsninfo->cnc_string,
                                               dsninfo->auth_string,
                                               GDA_CONNECTION_OPTIONS_NONE, &error);

        gtk_widget_destroy (window);

        if (!cnc) {
                g_print ("Could not open connection: %s\n",
                         error && error->message ? error->message : "No detail");
                exit (1);
        }

        /* execute a SELECT statement; here the easiest API is used */
        GdaDataModel *data_model;
        data_model = gda_execute_select_command (cnc, "SELECT * FROM customers", &error);
        if (!data_model) {
                g_print ("Could not execute the SQL command: %s\n",
                         error && error->message ? error->message : "No detail");
                /* close the connection */
                g_object_unref (cnc);
                exit (1);
        }
        
        /* Create a main window and show the data model in a grid */
        GtkWidget *grid;
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        grid = gdaui_grid_new (data_model);
        /*g_object_set (G_OBJECT (grid), "info-flags",
          GDAUI_DATA_PROXY_INFO_CURRENT_ROW | GDAUI_DATA_PROXY_INFO_ROW_MODIFY_BUTTONS, NULL);*/
        g_object_unref (data_model);
        gtk_container_add (GTK_CONTAINER (window), grid);
        gtk_widget_show_all (window);

        gtk_main();

        g_object_unref (cnc);

        return 0;
}

--- End code ---

cc -Wall -o sample sample.c `pkg-config --cflags --libs libgda-ui-4.0`

GTK Script? (back to the future)

JRS:
To get the ball rolling I thought I would post my almost completed definitions before starting on the actual meat of the program.


--- Code: ---' GNOME-DB GRID

' INTERFACE
DECLARE SUB DLL ALIAS "_gtk" LIB "gtk-server"
DECLARE SUB VARPTR ALIAS "varptr" LIB "gtk-server"

' GTK2
DLL("gtk_server_require libgtk-x11-2.0.so")
DLL("gtk_server_require libgdk-x11-2.0.so")
DLL("gtk_server_require libglib-2.0.so")
DLL("gtk_server_require libgobject-2.0.so")
DLL("gtk_server_require libatk-1.0.so")
DLL("gtk_server_require libpango-1.0.so")
DLL("gtk_server_require libgdk_pixbuf_xlib-2.0.so")

' GDA4
DLL("gtk_server_require libgda-4.0.so")
DLL("gtk_server_require libgda-ui-4.0.so")

' DECLARE
DLL("gtk_server_define gtk_init NONE NONE 2 NULL NULL")
' gtk_dialog_new_with_buttons
' gdaui_login_new
DLL("gtk_server_define gtk_box_pack_start NONE NONE 5 WIDGET WIDGET BOOL BOOL INT")
' gtk_dialog_get_content_area
DLL("gtk_server_define gtk_widget_show NONE NONE 1 WIDGET")
DLL("gtk_server_define gtk_dialog_run NONE INT 1 WIDGET")
' gdaui_login_get_connection_information
' gda_connection_open_from_string
DLL("gtk_server_define gtk_widget_destroy NONE NONE 1 WIDGET")
' gda_execute_select_command
DLL("gtk_server_define g_object_unref NONE NONE 1 WIDGET")
DLL("gtk_server_define gtk_window_new delete-event WIDGET 1 INT")
' gdaui_grid_new
DLL("gtk_server_define gtk_container_add NONE NONE 2 WIDGET WIDGET")
DLL("gtk_server_define gtk_widget_show_all NONE NONE 1 WIDGET")

--- End code ---


--- Quote from: THIN AIR ---hint: Get crackin', Son!!!
--- End quote ---

Escape from .hell with GTK-Server direct API interface.

AIR:

--- Quote from: JRS ---Escape from .hell with GTK-Server direct API interface.
--- End quote ---

Pfffft!



--- Code: ---$execon "-Os sample.c $(pkg-config --libs --cflags libgda-ui-4.0)"
$exestrip
$nomain
--- End code ---

It doesn't get any simpler!  ;D

This demonstrates how MBC/UBX/ConsoleBC/LinuxBC can leverage already debugged C code, and use it without having to go through the pain of a complete re-write. :P

Found a C function on the net you could use, but don't want to convert to BCX syntax?  Then don't, just use it as-is either between $ccode tags or like I did above.

BTW, I added the following to the sample.c source file so that the window (not the dialog) shows AND exits properly:

--- Code: ---        //~ ADDED BY AIR
        //~ ****************************************************************************
        g_object_set(G_OBJECT(window),"width-request",400,"height-request",200,NULL);
        g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
        //~ ****************************************************************************
--- End code ---

JRS:
Thanks for your BCX code challenge submission. Doesn't get much easier then that.  ;D

JRS:
Here is another GDA example that might be more of a challenge.


--- Code: ---#include <libgda/libgda.h>
#include <libgda/sql-parser/gda-sql-parser.h>

GdaConnection *open_connection (void);
void display_products_contents (GdaConnection *cnc);
void create_table (GdaConnection *cnc);
void insert_data (GdaConnection *cnc);
void update_data (GdaConnection *cnc);
void delete_data (GdaConnection *cnc);

void run_sql_non_select (GdaConnection *cnc, const gchar *sql);

int
main (int argc, char *argv[])
{
        gda_init ();

        GdaConnection *cnc;

/* open connections */
cnc = open_connection ();
create_table (cnc);

insert_data (cnc);
display_products_contents (cnc);

update_data (cnc);
display_products_contents (cnc);

delete_data (cnc);
display_products_contents (cnc);

        gda_connection_close (cnc);

        return 0;
}

/*
 * Open a connection to the example.db file
 */
GdaConnection *
open_connection ()
{
        GdaConnection *cnc;
        GError *error = NULL;
GdaSqlParser *parser;

/* open connection */
        cnc = gda_connection_open_from_string ("SQLite", "DB_DIR=.;DB_NAME=example_db", NULL,
       GDA_CONNECTION_OPTIONS_NONE,
       &error);
        if (!cnc) {
                g_print ("Could not open connection to SQLite database in example_db.db file: %s\n",
                         error && error->message ? error->message : "No detail");
                exit (1);
        }

/* create an SQL parser */
parser = gda_connection_create_parser (cnc);
if (!parser) /* @cnc doe snot provide its own parser => use default one */
parser = gda_sql_parser_new ();
/* attach the parser object to the connection */
g_object_set_data_full (G_OBJECT (cnc), "parser", parser, g_object_unref);

        return cnc;
}

/*
 * Create a "products" table
 */
void
create_table (GdaConnection *cnc)
{
run_sql_non_select (cnc, "DROP table IF EXISTS products");
        run_sql_non_select (cnc, "CREATE table products (ref string not null primary key, "
                            "name string not null, price real)");
}

/*
 * Insert some data
 *
 * Even though it is possible to use SQL text which includes the values to insert into the
 * table, it's better to use variables (place holders), or as is done here, convenience functions
 * to avoid SQL injection problems.
 */
void
insert_data (GdaConnection *cnc)
{
typedef struct {
gchar *ref;
gchar *name;

gboolean price_is_null;
gfloat price;
} RowData;
RowData data [] = {
{"p1", "chair", FALSE, 2.0},
{"p2", "table", FALSE, 5.0},
{"p3", "glass", FALSE, 1.1},
{"p1000", "???", TRUE, 0.},
{"p1001", "???", TRUE, 0.},
};
gint i;

gboolean res;
GError *error = NULL;
GValue *v1, *v2, *v3;

for (i = 0; i < sizeof (data) / sizeof (RowData); i++) {
v1 = gda_value_new_from_string (data[i].ref, G_TYPE_STRING);
v2 = gda_value_new_from_string (data[i].name, G_TYPE_STRING);
if (data[i].price_is_null)
v3 = NULL;
else {
v3 = gda_value_new (G_TYPE_FLOAT);
g_value_set_float (v3, data[i].price);
}

res = gda_insert_row_into_table (cnc, "products", &error, "ref", v1, "name", v2, "price", v3, NULL);

if (!res) {
g_error ("Could not INSERT data into the 'products' table: %s\n",
error && error->message ? error->message : "No detail");
}
gda_value_free (v1);
gda_value_free (v2);
if (v3)
gda_value_free (v3);
}
}

/*
 * Update some data
 */
void
update_data (GdaConnection *cnc)
{
gboolean res;
GError *error = NULL;
GValue *v1, *v2, *v3;

/* update data where ref is 'p1000' */
v1 = gda_value_new_from_string ("p1000", G_TYPE_STRING);
v2 = gda_value_new_from_string ("flowers", G_TYPE_STRING);
v3 = gda_value_new (G_TYPE_FLOAT);
g_value_set_float (v3, 1.99);

res = gda_update_row_in_table (cnc, "products", "ref", v1, &error, "name", v2, "price", v3, NULL);

if (!res) {
g_error ("Could not UPDATE data in the 'products' table: %s\n",
error && error->message ? error->message : "No detail");
}
gda_value_free (v1);
gda_value_free (v2);
gda_value_free (v3);
}

/*
 * Delete some data
 */
void
delete_data (GdaConnection *cnc)
{
gboolean res;
GError *error = NULL;
GValue *v;

/* delete data where name is 'table' */
v = gda_value_new_from_string ("table", G_TYPE_STRING);
res = gda_delete_row_from_table (cnc, "products", "name", v, &error);
if (!res) {
g_error ("Could not DELETE data from the 'products' table: %s\n",
error && error->message ? error->message : "No detail");
}
gda_value_free (v);

/* delete data where price is NULL */
res = gda_delete_row_from_table (cnc, "products", "price", NULL, &error);
if (!res) {
g_error ("Could not DELETE data from the 'products' table: %s\n",
error && error->message ? error->message : "No detail");
}
}

/*
 * display the contents of the 'products' table
 */
void
display_products_contents (GdaConnection *cnc)
{
GdaDataModel *data_model;
GdaSqlParser *parser;
GdaStatement *stmt;
gchar *sql = "SELECT ref, name, price FROM products";
GError *error = NULL;

parser = g_object_get_data (G_OBJECT (cnc), "parser");
stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
data_model = gda_connection_statement_execute_select (cnc, stmt, NULL, &error);
g_object_unref (stmt);
        if (!data_model)
                g_error ("Could not get the contents of the 'products' table: %s\n",
                         error && error->message ? error->message : "No detail");
gda_data_model_dump (data_model, stdout);
g_object_unref (data_model);
}

/*
 * run a non SELECT command and stops if an error occurs
 */
void
run_sql_non_select (GdaConnection *cnc, const gchar *sql)
{
        GdaStatement *stmt;
        GError *error = NULL;
        gint nrows;
const gchar *remain;
GdaSqlParser *parser;

parser = g_object_get_data (G_OBJECT (cnc), "parser");
stmt = gda_sql_parser_parse_string (parser, sql, &remain, &error);
if (remain)
g_print ("REMAINS: %s\n", remain);

        nrows = gda_connection_statement_execute_non_select (cnc, stmt, NULL, NULL, &error);
        if (nrows == -1)
                g_error ("NON SELECT error: %s\n", error && error->message ? error->message : "no detail");
g_object_unref (stmt);
}

--- End code ---

Navigation

[0] Message Index

[#] Next page

Go to full version