[GRASS-dev] string madness
Glynn Clements
glynn at gclements.plus.com
Sat Mar 17 19:58:25 EDT 2007
Wolf Bergenheim wrote:
> >> case SQLITE_INTEGER:
> >
> > This patch is entirely inappropriate. You're adding a hack to fix a
> > specific broken table. Instead, you need to figure out why the table
> > is getting created wrong in the first place. Once that's fixed, you
> > don't need this hack.
> >
>
> Well this occurs if you create an sqlite table with type date (sqlite
> allows this since sqlite is typeless and it won't complain).
>
> Then if you connect to it using v.db.connect, it will end up as a DOUBLE
> PRECISION layer which is bad. IMO it should default to VARCHAR(255)
>
> Here are the steps I did to reproduce this problem:
> first create a table in sqlite:
> create table foo(cat int, datum date);
> quit and now connect this to a vector map
>
> GRASS 6.3.cvs > v.db.connect layer=2 map=roads table=foo
> WARNING: The table <foo> is now part of vector map <roads> and may be
> deleted or overwritten by GRASS modules
> WARNING: Select privileges were granted on the table
>
> GRASS 6.3.cvs > v.info map=roads layer=2 -c
> Displaying column types/names for database connection of layer 2:
> INTEGER|cat
> DOUBLE PRECISION|datum
> ^^^^^^^^^^^^^^^^
> This is not right... it should be at least string...
>
> So in other words this might really be an issue... perhaps we should
> treat everything which is not numeric as a string when dealing with SQLite?
Yes. SQLite's db__driver_create_table() already does this if you
create the table that way.
I think that the problem is affinity_type (in describe.c):
int affinity_type ( const char *declared )
{
char *lc;
int aff = SQLITE_FLOAT;
lc = strdup ( declared );
G_tolcase ( lc );
if ( strstr(lc,"int") )
{
aff = SQLITE_INTEGER;
}
else if ( strstr(lc,"char") || strstr(lc,"clob")
|| strstr(lc,"text") )
{
aff = SQLITE_TEXT;
}
else if ( strstr(lc,"blob") )
{
aff = SQLITE_BLOB;
}
return aff;
}
But shouldn't get_column_info be using sqlite3_column_type() to get
SQLite's idea of the column type rather than trying to guess based
upon the declaration type? Oh; it already does that, but only if
there's no decltype:
decltype = sqlite3_column_decltype ( statement, col );
if ( decltype )
{
G_debug ( 4, "decltype = %s", decltype );
*litetype = affinity_type ( decltype );
}
else
{
G_debug ( 4, "this is not a table column" );
/* If there are no results it gives 0 */
*litetype = sqlite3_column_type ( statement, col );
}
Potential fixes (in descending order of preference):
1. Discard affinity_type() and always use sqlite3_column_type() for
the litetype.
2. Change affinity_type() to default to text (but then we need a list
of decltypes which should be treated as SQLITE_FLOAT).
3. Add strstr(lc, "date") to the SQLITE_TEXT case in affinity_type().
An additional improvement would be to modify get_column_info() to take
the decltype into account when determining the sqltype, rather than
only using the litetype. That would allow dates to be returned as
dates rather than as text. But I strongly feel that the litetype
should be what sqlite3_column_type() says it is, not what it "should"
be.
--
Glynn Clements <glynn at gclements.plus.com>
More information about the grass-dev
mailing list