之前困惑于GtkClist中数据类型与MySQL数据类型之间转换的问题,在gtk-app-dvel-list邮件列表上发了一个主题提问:

Arthur1989 says:

Hello, I used clist to display data iI fetch from mysql server,but when writing data back into the table of database, I got this question: the data type of clist is always gchar *, while there are quite a lot of other data types in mysql. What can I do to get this question solved? Any tips will be appreciated.

今天发现居然有人把实现的源码都贴到邮件里了..转到博客记下.

Shawn Bakhtlar(***@hotmail.com)replys:


//Ran into the same problem.

//I use a structure like

_IsiField {

	 int type,
	  int pos,
	   int ....

}

//Then create my own list with

_IsiList {

	 GList Fields;
	  GList rows;

}


//Every time retrieve a set of values, I have a routing which sets type to a G_TYPE, which corresponds to the MYSQL_TYPE


//Here is what I do:

GList *
isi_database_fetch_fields(IsiDatabase *self)
{

   MYSQL_FIELD *field;
   IsiFields *l;
   GList *gl = NULL;
   guint column = 0;

   /* Sanity Check */
   g_return_val_if_fail(self != NULL, NULL);
   g_return_val_if_fail(self->priv != NULL, NULL);
   g_return_val_if_fail(self->priv->dispose_has_run != TRUE, NULL);
   g_return_val_if_fail(self->priv->res != NULL, NULL);

   /* Rewind the feild set */
   mysql_field_seek(self->priv->res,0L);


   while((field = mysql_fetch_field(self->priv->res)))
   {
	   /* Initialize a new IsiFields structure */
	   //l = (IsiFields*) g_new0(IsiFields, 1);
	   l = g_new0(IsiFields, 1);

	   /* Set the values */
	   l->alias = g_strdup(field->name);
	   l->name = g_strdup(field->org_name);
	   l->length = field->length;

	   /* always make fields visable */

	   l->hidden = FALSE;
	   l->sortable = FALSE;
	   l->pos = column++;


	   switch (field->type){

		   /* Integer types */
		   case MYSQL_TYPE_TINY:
		   case MYSQL_TYPE_SHORT:
		   case MYSQL_TYPE_INT24:

			   /* Check for signage */
			   if (field->flags & UNSIGNED_FLAG)
				   l->type = G_TYPE_UINT;
			   else
				   l->type = G_TYPE_INT;

			   break;


			   /* Long types */
		   case MYSQL_TYPE_LONG:
		   case MYSQL_TYPE_LONGLONG:

			   /* Check for signage */
			   if (field->flags & UNSIGNED_FLAG)
				   l->type = G_TYPE_ULONG;
			   else
				   l->type = G_TYPE_LONG;
			   break;


			   /* Decimal types */
		   case MYSQL_TYPE_DECIMAL:
		   case MYSQL_TYPE_NEWDECIMAL:
		   case MYSQL_TYPE_FLOAT:
		   case MYSQL_TYPE_DOUBLE:
			   l->type = G_TYPE_DOUBLE;
			   break;

			   /* Bit types */
		   case MYSQL_TYPE_BIT:
			   l->type = G_TYPE_BOOLEAN;
			   break;

			   /* ENUM types */
		   case MYSQL_TYPE_ENUM:
			   l->type = G_TYPE_ENUM;
			   break;

			   /* All other types */
		   default:
		   case MYSQL_TYPE_STRING:
		   case MYSQL_TYPE_VAR_STRING:
		   case MYSQL_TYPE_BLOB:
		   case MYSQL_TYPE_SET:
		   case MYSQL_TYPE_TIMESTAMP:
		   case MYSQL_TYPE_DATE:
		   case MYSQL_TYPE_TIME:
		   case MYSQL_TYPE_DATETIME:
		   case MYSQL_TYPE_YEAR:
		   case MYSQL_TYPE_GEOMETRY:
		   case MYSQL_TYPE_NULL:

			   if(l->length <= 1){
				   l->type = G_TYPE_CHAR;
			   }else{
				   l->type = G_TYPE_STRING;
			   }
			   break;
	   }


	   /*DEBUG*/
	   //g_print("%s %d %d \n", l->alias,l->type,l->length);

	   /* Save pointer to list */
	   gl = g_list_append(gl,(gpointer)l);

   }

   return gl;
}



//now convert the row data to a GList and you have two GLists in your one lists, one with the field header info, the other with the data.
//and create the liststore like this:

GtkTreeModel *
isi_display_liststore_create(IsiDisplay *self, GList *fields)
{
	guint num_fields, i;
	IsiFields *l;
	GtkTreeModel *model;
	GType *types;
	guint search_col_adj = 0;

	/* Sanity Check */
	g_return_val_if_fail(self != NULL, NULL);
	g_return_val_if_fail(self->priv != NULL, NULL);
	g_return_val_if_fail(self->priv->dispose_has_run != TRUE, NULL);

	/* Get the number of fields */
	if(fields != NULL){

		num_fields = g_list_length(fields);

		/* Initialize values based on number of columns */
		types = (GType*) g_new0( GType, num_fields);

		for(i=0;i<num_fields;i++){

			l = (IsiFields*)g_list_nth_data(fields,i);
			types[i] = l->type;

		}

		/* create the model store for data input */
		model =  (GtkTreeModel*) gtk_list_store_newv(num_fields,types);

		g_free(types);

		for(i=0;i<num_fields;i++){

			l = (IsiFields*)g_list_nth_data(fields,i);

			/* Setup sorting functions for the modle */
			switch(l->type){
				case G_TYPE_INT:
					l->sortable=TRUE;
					gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), l->pos, sort_by_int,(gpointer) l->pos, NULL);
					break;
				case G_TYPE_UINT:
					l->sortable=TRUE;
					gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), l->pos, sort_by_uint,(gpointer) l->pos, NULL);
					break;
				case G_TYPE_LONG:
					l->sortable=TRUE;
					gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), l->pos, sort_by_long,(gpointer) l->pos, NULL);
					break;
				case G_TYPE_ULONG:
					l->sortable=TRUE;
					gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), l->pos, sort_by_ulong,(gpointer) l->pos, NULL);
					break;
				case G_TYPE_DOUBLE:
					l->sortable=TRUE;
					gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), l->pos, sort_by_double,(gpointer) l->pos, NULL);
					break;
				case G_TYPE_STRING:
					l->sortable=TRUE;
					gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), l->pos, sort_by_string,(gpointer) l->pos, NULL);
					break;
			}
		}

	return model;
}

//Hope this helps,
//Shawn

认真的看了一下,发现原来和自己想的差不多,都是事先记录好MySQL数据表中每列的数据类型,往回写时做个判断进行转换..只不过我是想用类似于map的字符串哈希映射实现的,这里变成了switch case罢了..

PS: 本文在vim下通过vimpress插件编辑发布,不知道浏览器看起来怎样,呵呵..