#include <sys/stat.h>
#include <sys/types.h>
#if defined(_WIN32)
#include <direct.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#if defined(_WIN32) && !defined(__MINGW32__)
#include "config-msvc.h"
#else
#include "config.h"
#endif
#include <spatialite/sqlite.h>
#include <spatialite/debug.h>
#include <spatialite/gaiaaux.h>
#include <spatialite/gaiageo.h>
#include <spatialite.h>
#include <spatialite_private.h>
#if defined(_WIN32) && !defined(__MINGW32__)
#define FRMT64 "%I64d"
#else
#define FRMT64 "%lld"
#endif
#if defined(_WIN32) && !defined(__MINGW32__)
#define strcasecmp _stricmp
#endif
struct validity_report_row
{
sqlite3_int64 rowid;
int valid;
char *warning;
char *error;
char *extra;
struct validity_report_row *next;
};
struct validity_report
{
struct validity_report_row *first;
struct validity_report_row *last;
int n_rows;
int n_nullgeoms;
int n_valids;
int n_invalids;
int n_warnings;
};
struct sanitize_report_row
{
sqlite3_int64 rowid;
int repaired;
char *warning;
char *error;
char *summary;
struct sanitize_report_row *next;
};
struct sanitize_report
{
struct sanitize_report_row *first;
struct sanitize_report_row *last;
int n_invalids;
int n_repaired;
int n_discarded;
int n_not_repaired;
int input_type;
int repaired_type;
int discarded_type;
};
static int
check_table_column (sqlite3 * sqlite, const char *table, const char *geom,
int *gtype, int *srid)
{
char *sql;
const char *xsql;
int ret;
int i;
char **results;
int rows;
int columns;
int spatial_type = 0;
int ok = 0;
*gtype = -1;
*srid = -2;
xsql = "SELECT CheckSpatialMetadata()";
ret = sqlite3_get_table (sqlite, xsql, &results, &rows, &columns, NULL);
if (ret != SQLITE_OK)
return 0;
if (rows < 1)
;
else
{
for (i = 1; i <= rows; i++)
spatial_type = atoi (results[(i * columns) + 0]);
}
sqlite3_free_table (results);
if (spatial_type == 1 || spatial_type == 3)
;
else
return 0;
if (spatial_type == 1)
xsql = "SELECT type, coord_dimension, srid FROM geometry_columns ";
else
xsql = "SELECT geometry_type, srid FROM geometry_columns ";
sql = sqlite3_mprintf ("%s WHERE Lower(f_table_name) = Lower(%Q) "
"AND Lower(f_geometry_column) = Lower(%Q)", xsql,
table, geom);
ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
sqlite3_free (sql);
if (ret != SQLITE_OK)
return 0;
if (rows < 1)
;
else
{
for (i = 1; i <= rows; i++)
{
ok = 1;
if (spatial_type == 1)
{
int ndims;
const char *type = results[(i * columns) + 0];
const char *dims = results[(i * columns) + 2];
if (strcasecmp (dims, "XYZM") == 0)
ndims = GAIA_XY_Z_M;
else if (strcasecmp (dims, "4") == 0)
ndims = GAIA_XY_Z_M;
else if (strcasecmp (dims, "XYZ") == 0)
ndims = GAIA_XY_Z;
else if (strcasecmp (dims, "3") == 0)
ndims = GAIA_XY_Z;
else if (strcasecmp (dims, "XYM") == 0)
ndims = GAIA_XY_M;
else
ndims = GAIA_XY;
if (strcasecmp (type, "POINT") == 0)
{
if (ndims == GAIA_XY_Z_M)
*gtype = 3001;
else if (ndims == GAIA_XY_Z)
*gtype = 1001;
else if (ndims == GAIA_XY_M)
*gtype = 2001;
else
*gtype = 1;
}
if (strcasecmp (type, "LINESTRING") == 0)
{
if (ndims == GAIA_XY_Z_M)
*gtype = 3002;
else if (ndims == GAIA_XY_Z)
*gtype = 1002;
else if (ndims == GAIA_XY_M)
*gtype = 2002;
else
*gtype = 2;
}
if (strcasecmp (type, "POLYGON") == 0)
{
if (ndims == GAIA_XY_Z_M)
*gtype = 3003;
else if (ndims == GAIA_XY_Z)
*gtype = 1003;
else if (ndims == GAIA_XY_M)
*gtype = 2003;
else
*gtype = 3;
}
if (strcasecmp (type, "MULTIPOINT") == 0)
{
if (ndims == GAIA_XY_Z_M)
*gtype = 3004;
else if (ndims == GAIA_XY_Z)
*gtype = 1004;
else if (ndims == GAIA_XY_M)
*gtype = 2004;
else
*gtype = 4;
}
if (strcasecmp (type, "MULTILINESTRING") == 0)
{
if (ndims == GAIA_XY_Z_M)
*gtype = 3005;
else if (ndims == GAIA_XY_Z)
*gtype = 1005;
else if (ndims == GAIA_XY_M)
*gtype = 2005;
else
*gtype = 5;
}
if (strcasecmp (type, "MULTIPOLYGON") == 0)
{
if (ndims == GAIA_XY_Z_M)
*gtype = 3006;
else if (ndims == GAIA_XY_Z)
*gtype = 1006;
else if (ndims == GAIA_XY_M)
*gtype = 2006;
else
*gtype = 6;
}
if (strcasecmp (type, "GEOMETRYCOLLECTION") == 0)
{
if (ndims == GAIA_XY_Z_M)
*gtype = 3007;
else if (ndims == GAIA_XY_Z)
*gtype = 1007;
else if (ndims == GAIA_XY_M)
*gtype = 2007;
else
*gtype = 7;
}
if (strcasecmp (type, "GEOMETRY") == 0)
{
if (ndims == GAIA_XY_Z_M)
*gtype = 3000;
else if (ndims == GAIA_XY_Z)
*gtype = 1000;
else if (ndims == GAIA_XY_M)
*gtype = 2000;
else
*gtype = 0;
}
*srid = atoi (results[(i * columns) + 1]);
}
else
{
*gtype = atoi (results[(i * columns) + 0]);
*srid = atoi (results[(i * columns) + 1]);
}
}
}
sqlite3_free_table (results);
return ok;
}
#ifdef ENABLE_LWGEOM
static struct sanitize_report *
alloc_sanitize_report (void)
{
struct sanitize_report *p = malloc (sizeof (struct sanitize_report));
p->first = NULL;
p->last = NULL;
p->n_invalids = 0;
p->n_repaired = 0;
p->n_discarded = 0;
p->n_not_repaired = 0;
p->input_type = -1;
p->repaired_type = -1;
p->discarded_type = -1;
return p;
}
static void
free_sanitize_report (struct sanitize_report *p)
{
struct sanitize_report_row *r;
struct sanitize_report_row *rn;
r = p->first;
while (r)
{
rn = r->next;
if (r->warning != NULL)
free (r->warning);
if (r->error != NULL)
free (r->error);
if (r->summary != NULL)
free (r->summary);
free (r);
r = rn;
}
free (p);
}
static void
addMessageToSanitizeReport (struct sanitize_report *report, sqlite3_int64 rowid,
int repaired, const char *error,
const char *warning, const char *summary)
{
int len;
struct sanitize_report_row *r =
malloc (sizeof (struct sanitize_report_row));
r->rowid = rowid;
r->repaired = repaired;
r->error = NULL;
r->warning = NULL;
r->summary = NULL;
r->next = NULL;
if (error)
{
len = strlen (error);
r->error = malloc (len + 1);
strcpy (r->error, error);
}
if (warning)
{
len = strlen (warning);
r->warning = malloc (len + 1);
strcpy (r->warning, warning);
}
if (summary)
{
len = strlen (summary);
r->summary = malloc (len + 1);
strcpy (r->summary, summary);
}
if (!repaired)
report->n_not_repaired += 1;
else
{
if (summary == NULL)
report->n_repaired += 1;
else
report->n_discarded += 1;
}
if (report->first == NULL)
report->first = r;
if (report->last != NULL)
report->last->next = r;
report->last = r;
}
static int
eval_type (int old, int new)
{
int o_dims;
int n_dims;
int r_dims;
int o_type;
int n_type;
int r_type;
int ret;
if (old < 0)
{
return new;
}
switch (old)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
o_dims = GAIA_XY;
break;
case 1000:
case 1001:
case 1002:
case 1003:
case 1004:
case 1005:
case 1006:
case 1007:
o_dims = GAIA_XY_Z;
break;
case 2000:
case 2001:
case 2002:
case 2003:
case 2004:
case 2005:
case 2006:
case 2007:
o_dims = GAIA_XY_M;
break;
case 3000:
case 3001:
case 3002:
case 3003:
case 3004:
case 3005:
case 3006:
case 3007:
o_dims = GAIA_XY_Z_M;
break;
default:
o_dims = GAIA_XY;
break;
};
switch (new)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
n_dims = GAIA_XY;
break;
case 1000:
case 1001:
case 1002:
case 1003:
case 1004:
case 1005:
case 1006:
case 1007:
n_dims = GAIA_XY_Z;
break;
case 2000:
case 2001:
case 2002:
case 2003:
case 2004:
case 2005:
case 2006:
case 2007:
n_dims = GAIA_XY_M;
break;
case 3000:
case 3001:
case 3002:
case 3003:
case 3004:
case 3005:
case 3006:
case 3007:
n_dims = GAIA_XY_Z_M;
break;
default:
n_dims = GAIA_XY;
break;
};
switch (old)
{
case 0:
case 1000:
case 2000:
case 3000:
o_type = -1;
break;
case 1:
case 1001:
case 2001:
case 3001:
o_type = GAIA_POINT;
break;
case 2:
case 1002:
case 2002:
case 3002:
o_type = GAIA_LINESTRING;
break;
case 3:
case 1003:
case 2003:
case 3003:
o_type = GAIA_POLYGON;
break;
case 4:
case 1004:
case 2004:
case 3004:
o_type = GAIA_MULTIPOINT;
break;
case 5:
case 1005:
case 2005:
case 3005:
o_type = GAIA_MULTILINESTRING;
break;
case 6:
case 1006:
case 2006:
case 3006:
o_type = GAIA_MULTIPOLYGON;
break;
case 7:
case 1007:
case 2007:
case 3007:
o_type = GAIA_GEOMETRYCOLLECTION;
break;
default:
o_type = -1;
break;
};
switch (new)
{
case 0:
case 1000:
case 2000:
case 3000:
n_type = -1;
break;
case 1:
case 1001:
case 2001:
case 3001:
n_type = GAIA_POINT;
break;
case 2:
case 1002:
case 2002:
case 3002:
n_type = GAIA_LINESTRING;
break;
case 3:
case 1003:
case 2003:
case 3003:
n_type = GAIA_POLYGON;
break;
case 4:
case 1004:
case 2004:
case 3004:
n_type = GAIA_MULTIPOINT;
break;
case 5:
case 1005:
case 2005:
case 3005:
n_type = GAIA_MULTILINESTRING;
break;
case 6:
case 1006:
case 2006:
case 3006:
n_type = GAIA_MULTIPOLYGON;
break;
case 7:
case 1007:
case 2007:
case 3007:
n_type = GAIA_GEOMETRYCOLLECTION;
break;
default:
n_type = -1;
break;
};
if (o_type == n_type)
r_type = n_type;
else
{
if ((o_type == GAIA_POINT || n_type == GAIA_POINT)
&& (o_type == GAIA_MULTIPOINT || n_type == GAIA_MULTIPOINT))
r_type = GAIA_MULTIPOINT;
else if ((o_type == GAIA_LINESTRING || n_type == GAIA_LINESTRING)
&& (o_type == GAIA_LINESTRING || n_type == GAIA_LINESTRING))
r_type = GAIA_MULTILINESTRING;
else if ((o_type == GAIA_POLYGON || n_type == GAIA_POLYGON)
&& (o_type == GAIA_MULTIPOLYGON
|| n_type == GAIA_MULTIPOLYGON))
r_type = GAIA_MULTIPOLYGON;
else
r_type = GAIA_GEOMETRYCOLLECTION;
}
if (o_dims == n_dims)
r_dims = n_dims;
else
{
if ((o_dims == GAIA_XY || n_dims == GAIA_XY)
&& (o_dims == GAIA_XY_Z || n_dims == GAIA_XY_Z))
r_dims = GAIA_XY_Z;
if ((o_dims == GAIA_XY || n_dims == GAIA_XY)
&& (o_dims == GAIA_XY_M || n_dims == GAIA_XY_M))
r_dims = GAIA_XY_M;
if ((o_dims == GAIA_XY || n_dims == GAIA_XY)
&& (o_dims == GAIA_XY_Z_M || n_dims == GAIA_XY_Z_M))
r_dims = GAIA_XY_Z_M;
if ((o_dims == GAIA_XY_M || n_dims == GAIA_XY_M)
&& (o_dims == GAIA_XY_Z || n_dims == GAIA_XY_Z))
r_dims = GAIA_XY_Z_M;
if ((o_dims == GAIA_XY_M || n_dims == GAIA_XY_M)
&& (o_dims == GAIA_XY_Z_M || n_dims == GAIA_XY_Z_M))
r_dims = GAIA_XY_Z_M;
if ((o_dims == GAIA_XY_Z || n_dims == GAIA_XY_Z)
&& (o_dims == GAIA_XY_Z_M || n_dims == GAIA_XY_Z_M))
r_dims = GAIA_XY_Z_M;
}
switch (r_type)
{
case GAIA_POINT:
switch (r_dims)
{
case GAIA_XY_Z_M:
ret = 3001;
break;
case GAIA_XY_Z:
ret = 1001;
break;
case GAIA_XY_M:
ret = 2001;
break;
case GAIA_XY:
ret = 1;
break;
};
break;
case GAIA_LINESTRING:
switch (r_dims)
{
case GAIA_XY_Z_M:
ret = 3002;
break;
case GAIA_XY_Z:
ret = 1002;
break;
case GAIA_XY_M:
ret = 2002;
break;
case GAIA_XY:
ret = 2;
break;
};
break;
case GAIA_POLYGON:
switch (r_dims)
{
case GAIA_XY_Z_M:
ret = 3003;
break;
case GAIA_XY_Z:
ret = 1003;
break;
case GAIA_XY_M:
ret = 2003;
break;
case GAIA_XY:
ret = 3;
break;
};
break;
case GAIA_MULTIPOINT:
switch (r_dims)
{
case GAIA_XY_Z_M:
ret = 3004;
break;
case GAIA_XY_Z:
ret = 1004;
break;
case GAIA_XY_M:
ret = 2004;
break;
case GAIA_XY:
ret = 4;
break;
};
break;
case GAIA_MULTILINESTRING:
switch (r_dims)
{
case GAIA_XY_Z_M:
ret = 3005;
break;
case GAIA_XY_Z:
ret = 1005;
break;
case GAIA_XY_M:
ret = 2005;
break;
case GAIA_XY:
ret = 5;
break;
};
break;
case GAIA_MULTIPOLYGON:
switch (r_dims)
{
case GAIA_XY_Z_M:
ret = 3006;
break;
case GAIA_XY_Z:
ret = 1006;
break;
case GAIA_XY_M:
ret = 2006;
break;
case GAIA_XY:
ret = 6;
break;
};
break;
default:
switch (r_dims)
{
case GAIA_XY_Z_M:
ret = 3007;
break;
case GAIA_XY_Z:
ret = 1007;
break;
case GAIA_XY_M:
ret = 2007;
break;
case GAIA_XY:
ret = 7;
break;
};
break;
};
return ret;
}
static int
eval_cast_type (int old, int new)
{
int o_type;
int n_type;
switch (old)
{
case 0:
case 1000:
case 2000:
case 3000:
o_type = -1;
break;
case 1:
case 1001:
case 2001:
case 3001:
o_type = GAIA_POINT;
break;
case 2:
case 1002:
case 2002:
case 3002:
o_type = GAIA_LINESTRING;
break;
case 3:
case 1003:
case 2003:
case 3003:
o_type = GAIA_POLYGON;
break;
case 4:
case 1004:
case 2004:
case 3004:
o_type = GAIA_MULTIPOINT;
break;
case 5:
case 1005:
case 2005:
case 3005:
o_type = GAIA_MULTILINESTRING;
break;
case 6:
case 1006:
case 2006:
case 3006:
o_type = GAIA_MULTIPOLYGON;
break;
case 7:
case 1007:
case 2007:
case 3007:
o_type = GAIA_GEOMETRYCOLLECTION;
break;
default:
o_type = -1;
break;
};
switch (new)
{
case 0:
case 1000:
case 2000:
case 3000:
n_type = -1;
break;
case 1:
case 1001:
case 2001:
case 3001:
n_type = GAIA_POINT;
break;
case 2:
case 1002:
case 2002:
case 3002:
n_type = GAIA_LINESTRING;
break;
case 3:
case 1003:
case 2003:
case 3003:
n_type = GAIA_POLYGON;
break;
case 4:
case 1004:
case 2004:
case 3004:
n_type = GAIA_MULTIPOINT;
break;
case 5:
case 1005:
case 2005:
case 3005:
n_type = GAIA_MULTILINESTRING;
break;
case 6:
case 1006:
case 2006:
case 3006:
n_type = GAIA_MULTIPOLYGON;
break;
case 7:
case 1007:
case 2007:
case 3007:
n_type = GAIA_GEOMETRYCOLLECTION;
break;
default:
n_type = -1;
break;
};
if (o_type == n_type)
return -1;
return n_type;
}
static int
eval_cast_dims (int old, int new)
{
int o_dims;
int n_dims;
switch (old)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
o_dims = GAIA_XY;
break;
case 1000:
case 1001:
case 1002:
case 1003:
case 1004:
case 1005:
case 1006:
case 1007:
o_dims = GAIA_XY_Z;
break;
case 2000:
case 2001:
case 2002:
case 2003:
case 2004:
case 2005:
case 2006:
case 2007:
o_dims = GAIA_XY_M;
break;
case 3000:
case 3001:
case 3002:
case 3003:
case 3004:
case 3005:
case 3006:
case 3007:
o_dims = GAIA_XY_Z_M;
break;
default:
o_dims = GAIA_XY;
break;
};
switch (new)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
n_dims = GAIA_XY;
break;
case 1000:
case 1001:
case 1002:
case 1003:
case 1004:
case 1005:
case 1006:
case 1007:
n_dims = GAIA_XY_Z;
break;
case 2000:
case 2001:
case 2002:
case 2003:
case 2004:
case 2005:
case 2006:
case 2007:
n_dims = GAIA_XY_M;
break;
case 3000:
case 3001:
case 3002:
case 3003:
case 3004:
case 3005:
case 3006:
case 3007:
n_dims = GAIA_XY_Z_M;
break;
default:
n_dims = GAIA_XY;
break;
};
if (o_dims == n_dims)
return -1;
return n_dims;
}
static const char *
createDiscardedSummary (gaiaGeomCollPtr geom, char *summary)
{
gaiaPointPtr pt;
gaiaLinestringPtr ln;
gaiaPolygonPtr pg;
int pts = 0;
int lns = 0;
int pgs = 0;
pt = geom->FirstPoint;
while (pt)
{
pts++;
pt = pt->Next;
}
ln = geom->FirstLinestring;
while (ln)
{
lns++;
ln = ln->Next;
}
pg = geom->FirstPolygon;
while (pg)
{
pgs++;
pg = pg->Next;
}
if (pts > 0 && lns == 0 && pgs == 0)
sprintf (summary, "%d Poin%s", pts, (pts > 1) ? "ts" : "t");
if (pts == 0 && lns > 0 && pgs == 0)
sprintf (summary, "%d Linestrin%s", lns, (lns > 1) ? "gs" : "g");
if (pts == 0 && lns == 0 && pgs > 0)
sprintf (summary, "%d Polygo%s", pgs, (pgs > 1) ? "ns" : "n");
if (pts > 0 && lns > 0 && pgs == 0)
sprintf (summary, "%d Poin%s; %d Linestrin%s", pts,
(pts > 1) ? "ts" : "t", lns, (lns > 1) ? "gs" : "s");
if (pts > 0 && lns == 0 && pgs > 0)
sprintf (summary, "%d Poin%s; %d Polygo%s", pts, (pts > 1) ? "ts" : "t",
pgs, (pgs > 1) ? "ns" : "n");
if (pts == 0 && lns > 0 && pgs > 0)
sprintf (summary, "%d Linestrin%s; %d Polygo%s", lns,
(lns > 1) ? "gs" : "g", pgs, (pgs > 1) ? "ns" : "n");
if (pts > 0 && lns > 0 && pgs > 0)
sprintf (summary, "%d Poin%s; %d Linestrin%s; %d Polygo%s", pts,
(pts > 1) ? "ts" : "t", lns, (lns > 1) ? "gs" : "s", pgs,
(pgs > 1) ? "ns" : "n");
return summary;
}
static int
change_geometry_type (sqlite3 * sqlite, const char *table, const char *geometry,
int cast_type, int cast_dims)
{
int ret;
int i;
char **results;
int rows;
int columns;
int spatial_type = 0;
const char *xsql;
char *sql;
sqlite3_stmt *stmt;
char *xtable;
char *xgeom;
const char *xtype;
const char *xdims;
xsql = "SELECT CheckSpatialMetadata()";
ret = sqlite3_get_table (sqlite, xsql, &results, &rows, &columns, NULL);
if (ret != SQLITE_OK)
return 0;
if (rows < 1)
;
else
{
for (i = 1; i <= rows; i++)
spatial_type = atoi (results[(i * columns) + 0]);
}
sqlite3_free_table (results);
if (spatial_type == 1 || spatial_type == 3)
;
else
return 0;
if (spatial_type == 1)
sql = sqlite3_mprintf ("UPDATE geometry_columns SET type = ?, "
"coord_dimension = ? WHERE Lower(f_table_name) = Lower(%Q) AND "
"Lower(f_geometry_column) = Lower(%Q)", table,
geometry);
else
sql = sqlite3_mprintf ("UPDATE geometry_columns SET geometry_type = ?, "
"coord_dimension = ? WHERE Lower(f_table_name) = Lower(%Q) AND "
"Lower(f_geometry_column) = Lower(%Q)", table,
geometry);
ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt, NULL);
sqlite3_free (sql);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
return 0;
}
sqlite3_reset (stmt);
sqlite3_clear_bindings (stmt);
if (spatial_type == 1)
{
const char *p_type = "GEOMETRY";
const char *p_dims = "XY";
switch (cast_type)
{
case GAIA_POINT:
p_type = "POINT";
break;
case GAIA_LINESTRING:
p_type = "LINESTRING";
break;
case GAIA_POLYGON:
p_type = "POLYGON";
break;
case GAIA_MULTIPOINT:
p_type = "MULTIPOINT";
break;
case GAIA_MULTILINESTRING:
p_type = "MULTILINESTRING";
break;
case GAIA_MULTIPOLYGON:
p_type = "MULTIPOLYGON";
break;
case GAIA_GEOMETRYCOLLECTION:
p_type = "GEOMETRYCOLLECTION";
break;
};
switch (cast_dims)
{
case GAIA_XY_Z_M:
p_dims = "XYZM";
break;
case GAIA_XY_Z:
p_dims = "XYZ";
break;
case GAIA_XY_M:
p_dims = "ZYM";
break;
};
sqlite3_bind_text (stmt, 1, p_type, strlen (p_type), SQLITE_STATIC);
sqlite3_bind_text (stmt, 2, p_dims, strlen (p_dims), SQLITE_STATIC);
}
else
{
int gtype = 0;
int ndims = 2;
switch (cast_type)
{
case GAIA_POINT:
switch (cast_dims)
{
case GAIA_XY_Z_M:
gtype = 3001;
ndims = 4;
break;
case GAIA_XY_Z:
gtype = 1001;
ndims = 3;
break;
case GAIA_XY_M:
gtype = 2001;
ndims = 3;
break;
default:
gtype = 1;
ndims = 2;
break;
};
break;
case GAIA_LINESTRING:
switch (cast_dims)
{
case GAIA_XY_Z_M:
gtype = 3002;
ndims = 4;
break;
case GAIA_XY_Z:
gtype = 1002;
ndims = 3;
break;
case GAIA_XY_M:
gtype = 2002;
ndims = 3;
break;
default:
gtype = 2;
ndims = 2;
break;
};
break;
case GAIA_POLYGON:
switch (cast_dims)
{
case GAIA_XY_Z_M:
gtype = 3003;
ndims = 4;
break;
case GAIA_XY_Z:
gtype = 1003;
ndims = 3;
break;
case GAIA_XY_M:
gtype = 2003;
ndims = 3;
break;
default:
gtype = 3;
ndims = 2;
break;
};
break;
case GAIA_MULTIPOINT:
switch (cast_dims)
{
case GAIA_XY_Z_M:
gtype = 3004;
ndims = 4;
break;
case GAIA_XY_Z:
gtype = 1004;
ndims = 3;
break;
case GAIA_XY_M:
gtype = 2004;
ndims = 3;
break;
default:
gtype = 4;
ndims = 2;
break;
};
break;
case GAIA_MULTILINESTRING:
switch (cast_dims)
{
case GAIA_XY_Z_M:
gtype = 3005;
ndims = 4;
break;
case GAIA_XY_Z:
gtype = 1005;
ndims = 3;
break;
case GAIA_XY_M:
gtype = 2005;
ndims = 3;
break;
default:
gtype = 5;
ndims = 2;
break;
};
break;
case GAIA_MULTIPOLYGON:
switch (cast_dims)
{
case GAIA_XY_Z_M:
gtype = 3006;
ndims = 4;
break;
case GAIA_XY_Z:
gtype = 1006;
ndims = 3;
break;
case GAIA_XY_M:
gtype = 2006;
ndims = 3;
break;
default:
gtype = 6;
ndims = 2;
break;
};
break;
case GAIA_GEOMETRYCOLLECTION:
switch (cast_dims)
{
case GAIA_XY_Z_M:
gtype = 3007;
ndims = 4;
break;
case GAIA_XY_Z:
gtype = 1007;
ndims = 3;
break;
case GAIA_XY_M:
gtype = 2007;
ndims = 3;
break;
default:
gtype = 7;
ndims = 2;
break;
};
break;
};
sqlite3_bind_int (stmt, 1, gtype);
sqlite3_bind_int (stmt, 2, ndims);
}
ret = sqlite3_step (stmt);
if (ret == SQLITE_DONE || ret == SQLITE_ROW)
;
else
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
return 0;
}
sqlite3_finalize (stmt);
xtable = gaiaDoubleQuotedSql (table);
xgeom = gaiaDoubleQuotedSql (geometry);
xtype = "Geometry";
xdims = "XY";
switch (cast_type)
{
case GAIA_POINT:
xtype = "Point";
break;
case GAIA_LINESTRING:
xtype = "Linestring";
break;
case GAIA_POLYGON:
xtype = "Polygon";
break;
case GAIA_MULTIPOINT:
xtype = "MultiPoint";
break;
case GAIA_MULTILINESTRING:
xtype = "MultiLinestring";
break;
case GAIA_MULTIPOLYGON:
xtype = "MultiPolygon";
break;
case GAIA_GEOMETRYCOLLECTION:
xtype = "GeometryCollection";
break;
};
switch (cast_dims)
{
case GAIA_XY_Z_M:
xdims = "XYZM";
break;
case GAIA_XY_Z:
xdims = "XYZ";
break;
case GAIA_XY_M:
xdims = "XYM";
break;
};
sql =
sqlite3_mprintf
("UPDATE \"%s\" SET \"%s\" = CastTo%s(CastTo%s(\"%s\"))", xtable, xgeom,
xtype, xdims, xgeom);
free (xtable);
free (xgeom);
ret = sqlite3_exec (sqlite, sql, NULL, 0, NULL);
sqlite3_free (sql);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
return 0;
}
return 1;
}
static void
drop_tmp_table (sqlite3 * sqlite, const char *tmp_table)
{
char *sql;
char *xtable;
int ret;
xtable = gaiaDoubleQuotedSql (tmp_table);
sql = sqlite3_mprintf ("DROP TABLE \"%s\"", xtable);
free (xtable);
ret = sqlite3_exec (sqlite, sql, NULL, 0, NULL);
sqlite3_free (sql);
if (ret != SQLITE_OK)
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
}
static void
update_repaired (sqlite3 * sqlite, const char *table, const char *geometry,
const char *tmp_table, int old_type, int new_type)
{
char *sql;
int cast_type = -1;
int cast_dims = -1;
int type;
char *xtmp_table;
char *xtable;
char *xgeom;
const char *casttype;
const char *castdims;
int ret;
int is_error = 0;
sqlite3_stmt *stmt;
sqlite3_stmt *stmt_out;
type = eval_type (old_type, new_type);
if (type != old_type)
{
cast_type = eval_cast_type (old_type, new_type);
cast_dims = eval_cast_dims (old_type, new_type);
}
xtmp_table = gaiaDoubleQuotedSql (tmp_table);
sql = sqlite3_mprintf ("SELECT ref_rowid, repaired_geometry FROM \"%s\" "
"WHERE repaired_geometry IS NOT NULL", xtmp_table);
free (xtmp_table);
ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt, NULL);
sqlite3_free (sql);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
goto stop;
}
xtable = gaiaDoubleQuotedSql (table);
xgeom = gaiaDoubleQuotedSql (geometry);
switch (new_type)
{
case 1:
casttype = "Point";
castdims = "XY";
break;
case 1001:
casttype = "Point";
castdims = "XYZ";
break;
case 2001:
casttype = "Point";
castdims = "XYM";
break;
case 3001:
casttype = "Point";
castdims = "XYZM";
break;
case 2:
casttype = "Linestring";
castdims = "XY";
break;
case 1002:
casttype = "Linestring";
castdims = "XYZ";
break;
case 2002:
casttype = "Linestring";
castdims = "XYM";
break;
case 3002:
casttype = "Linestring";
castdims = "XYZM";
break;
case 3:
casttype = "Polygon";
castdims = "XY";
break;
case 1003:
casttype = "Polygon";
castdims = "XYZ";
break;
case 2003:
casttype = "Polygon";
castdims = "XYM";
break;
case 3003:
casttype = "Polygon";
castdims = "XYZM";
break;
case 4:
casttype = "MultiPoint";
castdims = "XY";
break;
case 1004:
casttype = "MultiPoint";
castdims = "XYZ";
break;
case 2004:
casttype = "MultiPoint";
castdims = "XYM";
break;
case 3004:
casttype = "MultiPoint";
castdims = "XYZM";
break;
case 5:
casttype = "MultiLinestring";
castdims = "XY";
break;
case 1005:
casttype = "MultiLinestring";
castdims = "XYZ";
break;
case 2005:
casttype = "MultiLinestring";
castdims = "XYM";
break;
case 3005:
casttype = "MultiLinestring";
castdims = "XYZM";
break;
case 6:
casttype = "MultiPolygon";
castdims = "XY";
break;
case 1006:
casttype = "MultiPolygon";
castdims = "XYZ";
break;
case 2006:
casttype = "MultiPolygon";
castdims = "XYM";
break;
case 3006:
casttype = "MultiPolygon";
castdims = "XYZM";
break;
case 7:
casttype = "GeometryCollection";
castdims = "XY";
break;
case 1007:
casttype = "GeometryCollection";
castdims = "XYZ";
break;
case 2007:
casttype = "GeometryCollection";
castdims = "XYM";
break;
case 3007:
casttype = "GeometryCollection";
castdims = "XYZM";
break;
case 0:
casttype = "Multi";
castdims = "XY";
break;
case 1000:
casttype = "Multi";
castdims = "XYZ";
break;
case 2000:
casttype = "Multi";
castdims = "XYM";
break;
case 3000:
casttype = "Multi";
castdims = "XYZM";
break;
default:
casttype = "Multi";
castdims = "XY";
break;
};
sql = sqlite3_mprintf ("UPDATE \"%s\" SET \"%s\" = CastTo%s(CastTo%s(?)) "
"WHERE ROWID = ?", xtable, xgeom, casttype,
castdims);
free (xtable);
free (xgeom);
ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt_out, NULL);
sqlite3_free (sql);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
goto stop;
}
ret = sqlite3_exec (sqlite, "BEGIN", NULL, 0, NULL);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
goto stop;
}
if (cast_type != -1 || cast_dims != -1)
{
if (!change_geometry_type
(sqlite, table, geometry, cast_type, cast_dims))
return;
}
while (1)
{
ret = sqlite3_step (stmt);
if (ret == SQLITE_DONE)
break;
if (ret == SQLITE_ROW)
{
sqlite3_int64 rowid = sqlite3_column_int (stmt, 0);
if (sqlite3_column_type (stmt, 1) == SQLITE_BLOB)
{
const unsigned char *blob = sqlite3_column_blob (stmt, 1);
int n_bytes = sqlite3_column_bytes (stmt, 1);
sqlite3_reset (stmt_out);
sqlite3_clear_bindings (stmt_out);
sqlite3_bind_blob (stmt_out, 1, blob, n_bytes,
SQLITE_STATIC);
sqlite3_bind_int64 (stmt_out, 2, rowid);
ret = sqlite3_step (stmt_out);
if (ret == SQLITE_DONE || ret == SQLITE_ROW)
;
else
{
is_error = 1;
spatialite_e
("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
break;
}
}
}
else
{
spatialite_e ("check_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
break;
}
}
sqlite3_finalize (stmt);
sqlite3_finalize (stmt_out);
if (is_error)
{
ret = sqlite3_exec (sqlite, "ROLLBACK", NULL, 0, NULL);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
goto stop;
}
goto stop;
}
else
{
drop_tmp_table (sqlite, tmp_table);
ret = sqlite3_exec (sqlite, "COMMIT", NULL, 0, NULL);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
goto stop;
}
}
stop:
return;
}
static int
sanitize_geometry_column_common (const void *p_cache, sqlite3 * sqlite,
const char *table, const char *geom,
const char *tmp_table, const char *report_path,
int *n_invalids, int *n_repaired,
int *n_discarded, int *n_failures,
char **err_msg)
{
#ifdef ENABLE_LWGEOM
char *sql;
char *xtable;
char *xgeom;
char *xtmp_table;
sqlite3_stmt *stmt;
sqlite3_stmt *stmt_out;
int ret;
int gtype;
int srid;
const char *x_type;
const char *x_dims;
char num[256];
FILE *out = NULL;
const char *p_msg;
const char *p_summary;
char summary[1024];
int is_error = 0;
time_t v_time;
struct tm *v_tm;
const char *day;
const char *month;
int len;
struct sanitize_report_row *p_r;
struct sanitize_report *report = alloc_sanitize_report ();
if (err_msg != NULL)
*err_msg = NULL;
if (!check_table_column (sqlite, table, geom, >ype, &srid))
{
spatialite_e ("sanitize_geometry_column error: <%s><%s>\n"
"Not defined in \"geometry_columns\"", table, geom);
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf
("sanitize_geometry_column error: <%s><%s>\n"
"Not defined in \"geometry_columns\"", table, geom);
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
goto stop;
}
switch (gtype)
{
case 0:
x_type = "GEOMETRY";
x_dims = "XY";
break;
case 1000:
x_type = "GEOMETRY";
x_dims = "XYZ";
break;
case 2000:
x_type = "GEOMETRY";
x_dims = "XYM";
break;
case 3000:
x_type = "GEOMETRY";
x_dims = "XYZM";
break;
case 1:
x_type = "POINT";
x_dims = "XY";
break;
case 1001:
x_type = "POINT";
x_dims = "XYZ";
break;
case 2001:
x_type = "POINT";
x_dims = "XYM";
break;
case 3001:
x_type = "POINT";
x_dims = "XYZM";
break;
case 2:
x_type = "LINESTRING";
x_dims = "XY";
break;
case 1002:
x_type = "LINESTRING";
x_dims = "XYZ";
break;
case 2002:
x_type = "LINESTRING";
x_dims = "XYM";
break;
case 3002:
x_type = "LINESTRING";
x_dims = "XYZM";
break;
case 3:
x_type = "POLYGON";
x_dims = "XY";
break;
case 1003:
x_type = "POLYGON";
x_dims = "XYZ";
break;
case 2003:
x_type = "POLYGON";
x_dims = "XYM";
break;
case 3003:
x_type = "POLYGON";
x_dims = "XYZM";
break;
case 4:
x_type = "MULTIPOINT";
x_dims = "XY";
break;
case 1004:
x_type = "MULTIPOINT";
x_dims = "XYZ";
break;
case 2004:
x_type = "MULTIPOINT";
x_dims = "XYM";
break;
case 3004:
x_type = "MULTIPOINT";
x_dims = "XYZM";
break;
case 5:
x_type = "MULTILINESTRING";
x_dims = "XY";
break;
case 1005:
x_type = "MULTILINESTRING";
x_dims = "XYZ";
break;
case 2005:
x_type = "MULTILINESTRING";
x_dims = "XYM";
break;
case 3005:
x_type = "MULTILINESTRING";
x_dims = "XYZM";
break;
case 6:
x_type = "MULTIPOLYGON";
x_dims = "XY";
break;
case 1006:
x_type = "MULTIPOLYGON";
x_dims = "XYZ";
break;
case 2006:
x_type = "MULTIPOLYGON";
x_dims = "XYM";
break;
case 3006:
x_type = "MULTIPOLYGON";
x_dims = "XYZM";
break;
case 7:
x_type = "GEOMETRYCOLLECTION";
x_dims = "XY";
break;
case 1007:
x_type = "GEOMETRYCOLLECTION";
x_dims = "XYZ";
break;
case 2007:
x_type = "GEOMETRYCOLLECTION";
x_dims = "XYM";
break;
case 3007:
x_type = "GEOMETRYCOLLECTION";
x_dims = "XYZM";
break;
default:
x_type = "UNKNOWN";
x_dims = "UNKNOWN";
break;
};
xtable = gaiaDoubleQuotedSql (table);
xgeom = gaiaDoubleQuotedSql (geom);
sql = sqlite3_mprintf ("SELECT ROWID, \"%s\" FROM \"%s\"", xgeom, xtable);
free (xtable);
free (xgeom);
ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt, NULL);
sqlite3_free (sql);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
goto stop;
}
xtmp_table = gaiaDoubleQuotedSql (tmp_table);
sql =
sqlite3_mprintf
("CREATE TABLE \"%s\" (ref_rowid INTEGER NOT NULL PRIMARY KEY, "
"input_geometry BLOB, repaired_geometry BLOB, discarded_geometry BLOB)",
xtmp_table);
free (xtmp_table);
ret = sqlite3_exec (sqlite, sql, NULL, 0, NULL);
sqlite3_free (sql);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
goto stop;
}
xtmp_table = gaiaDoubleQuotedSql (tmp_table);
sql = sqlite3_mprintf ("INSERT INTO \"%s\" "
"(ref_rowid, input_geometry, repaired_geometry, discarded_geometry) "
"VALUES (?, ?, ?, ?)", xtmp_table);
free (xtmp_table);
ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt_out, NULL);
sqlite3_free (sql);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
goto stop;
}
ret = sqlite3_exec (sqlite, "BEGIN", NULL, 0, NULL);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
goto stop;
}
out = fopen (report_path, "wb");
if (out == NULL)
goto stop;
while (1)
{
ret = sqlite3_step (stmt);
if (ret == SQLITE_DONE)
break;
if (ret == SQLITE_ROW)
{
gaiaGeomCollPtr geom = NULL;
sqlite3_int64 rowid = sqlite3_column_int (stmt, 0);
if (sqlite3_column_type (stmt, 1) == SQLITE_BLOB)
{
const unsigned char *blob = sqlite3_column_blob (stmt, 1);
int n_bytes = sqlite3_column_bytes (stmt, 1);
geom = gaiaFromSpatiaLiteBlobWkb (blob, n_bytes);
}
if (geom)
{
int valret;
if (p_cache != NULL)
{
gaiaResetGeosMsg_r (p_cache);
valret = gaiaIsValid_r (p_cache, geom);
}
else
{
gaiaResetGeosMsg ();
valret = gaiaIsValid (geom);
}
if (!valret)
{
unsigned char *blob_geom;
int blob_sz_geom;
unsigned char *blob_saned;
int blob_sz_saned;
unsigned char *blob_dscrd;
int blob_sz_dscrd;
const char *error;
const char *warning;
gaiaGeomCollPtr repaired;
gaiaGeomCollPtr discarded;
report->n_invalids += 1;
gaiaResetLwGeomMsg ();
repaired = gaiaMakeValid (geom);
discarded = gaiaMakeValidDiscarded (geom);
error = gaiaGetLwGeomErrorMsg ();
warning = gaiaGetLwGeomWarningMsg ();
if (discarded == NULL)
p_summary = NULL;
else
p_summary =
createDiscardedSummary (discarded, summary);
addMessageToSanitizeReport (report, rowid,
(repaired ==
NULL) ? 0 : 1, error,
warning, p_summary);
sqlite3_reset (stmt_out);
sqlite3_clear_bindings (stmt_out);
sqlite3_bind_int64 (stmt_out, 1, rowid);
if (!repaired)
{
report->input_type =
eval_type (report->input_type,
gaiaGeometryType (geom));
gaiaToSpatiaLiteBlobWkb (geom, &blob_geom,
&blob_sz_geom);
sqlite3_bind_blob (stmt_out, 2, blob_geom,
blob_sz_geom, free);
sqlite3_bind_null (stmt_out, 3);
}
else
{
report->repaired_type =
eval_type (report->repaired_type,
gaiaGeometryType (repaired));
sqlite3_bind_null (stmt_out, 2);
gaiaToSpatiaLiteBlobWkb (repaired,
&blob_saned,
&blob_sz_saned);
sqlite3_bind_blob (stmt_out, 3, blob_saned,
blob_sz_saned, free);
}
if (discarded)
{
report->discarded_type =
eval_type (report->discarded_type,
gaiaGeometryType (discarded));
gaiaToSpatiaLiteBlobWkb (discarded,
&blob_dscrd,
&blob_sz_dscrd);
sqlite3_bind_blob (stmt_out, 4, blob_dscrd,
blob_sz_dscrd, free);
}
else
sqlite3_bind_null (stmt_out, 4);
ret = sqlite3_step (stmt_out);
if (ret == SQLITE_DONE || ret == SQLITE_ROW)
;
else
{
is_error = 1;
spatialite_e
("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf
("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
break;
}
if (repaired)
gaiaFreeGeomColl (repaired);
if (discarded)
gaiaFreeGeomColl (discarded);
}
gaiaFreeGeomColl (geom);
}
}
else
{
spatialite_e ("check_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf
("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
break;
}
}
sqlite3_finalize (stmt);
sqlite3_finalize (stmt_out);
if (is_error)
{
ret = sqlite3_exec (sqlite, "ROLLBACK", NULL, 0, NULL);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf
("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
goto stop;
}
goto stop;
}
else
{
ret = sqlite3_exec (sqlite, "COMMIT", NULL, 0, NULL);
if (ret != SQLITE_OK)
{
spatialite_e ("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf
("sanitize_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
goto stop;
}
}
fprintf (out,
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
fprintf (out, "<html>\n\t<head>\n");
fprintf (out,
"\t\t<meta content=\"text/html; charset=UTF-8\" http-equiv=\"content-type\">\n");
fprintf (out,
"\t\t<title>SpatiaLite Repair Geometries - Table: %s</title>\n",
table);
fprintf (out, "\t\t<style type=\"text/css\">\n");
fprintf (out, "\t\t\th1 {color:red;}\n");
fprintf (out, "\t\t\th2 {color:navy;}\n");
fprintf (out, "\t\t\ttd.title {background-color:silver;}\n");
fprintf (out, "\t\t\ttd.ok {background-color:#00ff00;}\n");
fprintf (out, "\t\t\ttd.err {background-color:#ff0000;}\n");
fprintf (out, "\t\t\ttd.wng {background-color:#ffff00;}\n");
fprintf (out, "\t\t</style>\n");
fprintf (out, "\t</head>\n\t<body bgcolor=\"#f8fff8\">\n");
time (&v_time);
v_tm = localtime (&v_time);
switch (v_tm->tm_wday)
{
case 0:
day = "Sun";
break;
case 1:
day = "Mon";
break;
case 2:
day = "Tue";
break;
case 3:
day = "Wed";
break;
case 4:
day = "Thu";
break;
case 5:
day = "Fri";
break;
case 6:
day = "Sat";
break;
};
switch (v_tm->tm_mon)
{
case 0:
month = "Jan";
break;
case 1:
month = "Feb";
break;
case 2:
month = "Mar";
break;
case 3:
month = "Apr";
break;
case 4:
month = "May";
break;
case 5:
month = "Jun";
break;
case 6:
month = "Jul";
break;
case 7:
month = "Aug";
break;
case 8:
month = "Sep";
break;
case 9:
month = "Oct";
break;
case 10:
month = "Nov";
break;
case 11:
month = "Dec";
break;
};
fprintf (out, "\t\t%d-%s-%d, %s [%02d:%02d:%02d]<br>\n",
v_tm->tm_year + 1900, month, v_tm->tm_mday, day, v_tm->tm_hour,
v_tm->tm_min, v_tm->tm_sec);
fprintf (out, "\t\t<h1>SpatiaLite Repair Geometries</h1>\n");
fprintf (out, "\t\t<h2>Summary</h2>\n");
fprintf (out,
"\t\t<table cellspacing=\"4\" callpadding=\"4\" border=\"1\">\n");
fprintf (out,
"\t\t\t<tr><td class=\"title\" colspan=\"2\" align=\"center\">Table / Layer</td></tr>\n");
fprintf (out, "\t\t\t<tr><td>Table</td><td>%s</td></tr>\n", table);
fprintf (out, "\t\t\t<tr><td>Geometry Column</td><td>%s</td></tr>\n", geom);
fprintf (out, "\t\t\t<tr><td>Geometry Type</td><td>%s</td></tr>\n", x_type);
fprintf (out, "\t\t\t<tr><td>Dimensions</td><td>%s</td></tr>\n", x_dims);
fprintf (out, "\t\t\t<tr><td>SRID</td><td align=\"right\">%d</td></tr>\n",
srid);
fprintf (out,
"\t\t\t<tr><td class=\"title\" colspan=\"2\" align=\"center\">Statistics</td></tr>\n");
fprintf (out,
"\t\t\t<tr><td>Invalid Geometries</td><td align=\"right\">%d</td></tr>\n",
report->n_invalids);
if (report->n_repaired > 0)
fprintf (out,
"\t\t\t<tr><td>Repaired Geometries (fully recovered)</td><td class=\"ok\" align=\"right\">%d</td></tr>\n",
report->n_repaired);
else
fprintf (out,
"\t\t\t<tr><td>Repaired Geometries (fully recovered)</td><td align=\"right\">NONE</td></tr>\n");
if (report->n_discarded > 0)
fprintf (out,
"\t\t\t<tr><td>Repaired Geometries (by discarding fragments)</td><td class=\"wng\" align=\"right\">%d</td></tr>\n",
report->n_discarded);
else
fprintf (out,
"\t\t\t<tr><td>Repaired Geometries (by discarding fragments)</td><td align=\"right\">NONE</td></tr>\n");
if (report->n_not_repaired > 0)
fprintf (out,
"\t\t\t<tr><td>Failures (Not Repaired Geometries)</td><td class=\"err\" align=\"right\">%d</td></tr>\n",
report->n_not_repaired);
else
fprintf (out,
"\t\t\t<tr><td>Failures (Not Repaired Geometries)</td><td align=\"right\">NONE</td></tr>\n");
fprintf (out,
"\t\t\t<tr><td class=\"title\" colspan=\"2\" align=\"center\">Suggested Action</td></tr>\n");
if (report->n_not_repaired > 0)
{
fprintf (out,
"\t\t\t<tr><td colspan=\"2\" class=\"err\">This layer contains severly damaged Geometries (beyond any possible repair);<br>");
fprintf (out,
"please manually check the <b>%s</b> table.</td></tr>\n",
tmp_table);
}
else if (report->n_discarded > 0)
{
fprintf (out,
"\t\t\t<tr><td colspan=\"2\" class=\"wng\">This layer contains valid but dubious Geometries;<br>");
fprintf (out, "a repair action is suggested.</td></tr>\n");
}
else if (report->n_repaired > 0)
{
fprintf (out,
"\t\t\t<tr><td colspan=\"2\" class=\"ok\">This layer has been successfully repaired and is now completely valid;<br>");
fprintf (out,
"doesn't require any further corrective action.</td></tr>\n");
}
else
{
fprintf (out,
"\t\t\t<tr><td colspan=\"2\" class=\"ok\">This layer already was completely valid;<br>");
fprintf (out, "no corrective action was applied.</td></tr>\n");
}
fprintf (out, "\t\t</table>\n");
if (report->n_not_repaired != 0)
{
fprintf (out, "\t\t\t<hr>\n\t\t<h2>Not Repaired Geometries</h2>\n");
fprintf (out,
"\t\t<table cellspacing=\"4\" callpadding=\"4\" border=\"1\">\n");
fprintf (out,
"\t\t\t<tr><td class=\"title\" align=\"center\">ROWID</td>");
fprintf (out, "<td class=\"title\" align=\"center\">Status</td>");
fprintf (out,
"<td class=\"title\" align=\"center\">Error Message</td></tr>\n");
p_r = report->first;
while (p_r)
{
if (p_r->repaired != 0)
{
p_r = p_r->next;
continue;
}
sprintf (num, FRMT64, p_r->rowid);
p_msg = "Unknown cause";
if (p_r->error)
p_msg = p_r->error;
else if (p_r->warning)
p_msg = p_r->warning;
fprintf (out,
"\t\t\t<tr><td align=\"right\">%s</td><td class=\"err\">Not Repaired (beyond possible repair)</td><td>%s</td></tr>\n",
num, p_msg);
p_r = p_r->next;
}
fprintf (out, "\t\t</table>\n");
}
if (report->n_discarded != 0)
{
fprintf (out,
"\t\t\t<hr>\n\t\t<h2>Repaired Geometries (by discarding fragments)</h2>\n");
fprintf (out,
"\t\t<table cellspacing=\"4\" callpadding=\"4\" border=\"1\">\n");
fprintf (out,
"\t\t\t<tr><td class=\"title\" align=\"center\">ROWID</td>");
fprintf (out, "<td class=\"title\" align=\"center\">Status</td>");
fprintf (out,
"<td class=\"title\" align=\"center\">Discarded fragments summary</td></tr>\n");
p_r = report->first;
while (p_r)
{
if (p_r->summary == NULL)
{
p_r = p_r->next;
continue;
}
sprintf (num, FRMT64, p_r->rowid);
fprintf (out,
"\t\t\t<tr><td align=\"right\">%s</td><td class=\"wng\">Repaired by discarding fragments</td><td>%s</td></tr>\n",
num, p_r->summary);
p_r = p_r->next;
}
fprintf (out, "\t\t</table>\n");
}
fprintf (out, "\t</body>\n</html>\n");
fclose (out);
if (report->n_invalids == 0)
{
drop_tmp_table (sqlite, tmp_table);
}
if (report->n_repaired > 0 && report->n_discarded == 0
&& report->n_not_repaired == 0)
{
update_repaired (sqlite, table, geom, tmp_table, gtype,
report->repaired_type);
}
if (n_invalids != NULL)
*n_invalids = report->n_invalids;
if (n_repaired != NULL)
*n_repaired = report->n_repaired;
if (n_discarded != NULL)
*n_discarded = report->n_discarded;
if (n_failures != NULL)
*n_failures = report->n_not_repaired;
free_sanitize_report (report);
return 1;
stop:
free_sanitize_report (report);
if (out)
fclose (out);
#endif
return 0;
}
SPATIALITE_DECLARE int
sanitize_geometry_column (sqlite3 * sqlite, const char *table, const char *geom,
const char *tmp_table, const char *report_path,
int *n_invalids, int *n_repaired, int *n_discarded,
int *n_failures, char **err_msg)
{
return sanitize_geometry_column_common (NULL, sqlite, table, geom,
tmp_table, report_path, n_invalids,
n_repaired, n_discarded, n_failures,
err_msg);
}
SPATIALITE_DECLARE int
sanitize_geometry_column_r (const void *p_cache, sqlite3 * sqlite,
const char *table, const char *geom,
const char *tmp_table, const char *report_path,
int *n_invalids, int *n_repaired, int *n_discarded,
int *n_failures, char **err_msg)
{
return sanitize_geometry_column_common (p_cache, sqlite, table, geom,
tmp_table, report_path, n_invalids,
n_repaired, n_discarded, n_failures,
err_msg);
}
static int
sanitize_all_geometry_columns_common (const void *p_cache, sqlite3 * sqlite,
const char *tmp_prefix,
const char *output_dir,
int *x_not_repaired, char **err_msg)
{
const char *sql;
int ret;
int i;
char **results;
int rows;
int columns;
int n_invalids;
int n_repaired;
int n_discarded;
int n_failures;
char *report;
char *tmp_table;
FILE *out = NULL;
time_t v_time;
struct tm *v_tm;
const char *day;
const char *month;
int sum_not_repaired = 0;
if (err_msg != NULL)
*err_msg = NULL;
#if defined(_WIN32)
_mkdir (output_dir);
#else
mkdir (output_dir, 0777);
#endif
report = sqlite3_mprintf ("%s/index.html", output_dir);
out = fopen (report, "wb");
sqlite3_free (report);
if (out == NULL)
goto stop;
fprintf (out,
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
fprintf (out, "<html>\n\t<head>\n");
fprintf (out,
"\t\t<meta content=\"text/html; charset=UTF-8\" http-equiv=\"content-type\">\n");
fprintf (out,
"\t\t<title>SpatiaLite Repair Geometries - All Tables</title>\n");
fprintf (out, "\t\t<style type=\"text/css\">\n");
fprintf (out, "\t\t\th1 {color:navy;}\n");
fprintf (out, "\t\t\ttd.title {background-color:silver;}\n");
fprintf (out, "\t\t\ttd.ok {background-color:#00ff00;}\n");
fprintf (out, "\t\t\ttd.err {background-color:#ff0000;}\n");
fprintf (out, "\t\t\ttd.wng {background-color:#ffff00;}\n");
fprintf (out, "\t\t\ttd.nil {background-color:#ffffff;}\n");
fprintf (out, "\t\t</style>\n");
fprintf (out, "\t</head>\n\t<body bgcolor=\"#f8fff8\">\n");
time (&v_time);
v_tm = localtime (&v_time);
switch (v_tm->tm_wday)
{
case 0:
day = "Sun";
break;
case 1:
day = "Mon";
break;
case 2:
day = "Tue";
break;
case 3:
day = "Wed";
break;
case 4:
day = "Thu";
break;
case 5:
day = "Fri";
break;
case 6:
day = "Sat";
break;
};
switch (v_tm->tm_mon)
{
case 0:
month = "Jan";
break;
case 1:
month = "Feb";
break;
case 2:
month = "Mar";
break;
case 3:
month = "Apr";
break;
case 4:
month = "May";
break;
case 5:
month = "Jun";
break;
case 6:
month = "Jul";
break;
case 7:
month = "Aug";
break;
case 8:
month = "Sep";
break;
case 9:
month = "Oct";
break;
case 10:
month = "Nov";
break;
case 11:
month = "Dec";
break;
};
fprintf (out, "\t\t%d-%s-%d, %s [%02d:%02d:%02d]<br>\n",
v_tm->tm_year + 1900, month, v_tm->tm_mday, day, v_tm->tm_hour,
v_tm->tm_min, v_tm->tm_sec);
fprintf (out, "\t\t<h1>SpatiaLite Repair Geometries</h1>\n");
fprintf (out,
"\t\t<table cellspacing=\"4\" callpadding=\"4\" border=\"1\">\n");
fprintf (out,
"\t\t\t<tr><td class=\"title\" align=\"center\">Show Details</td>");
fprintf (out, "<td class=\"title\" align=\"center\">Table</td>");
fprintf (out, "<td class=\"title\" align=\"center\">Geometry</td>");
fprintf (out,
"<td class=\"title\" align=\"center\">Invalid Geometries</td>");
fprintf (out,
"<td class=\"title\" align=\"center\">Repaired Geometries</td>");
fprintf (out,
"<td class=\"title\" align=\"center\">Repaired Geometries<br>(by Discarding Fragments)</td>");
fprintf (out,
"<td class=\"title\" align=\"center\">Repair Failures<br>(beyond possible repair)</td>");
fprintf (out,
"<td class=\"title\" align=\"center\">Suggested Action</td></tr>\n");
sql = "SELECT f_table_name, f_geometry_column FROM geometry_columns";
ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
if (ret != SQLITE_OK)
goto stop;
if (rows < 1)
;
else
{
for (i = 1; i <= rows; i++)
{
const char *cls_1;
const char *cls_2;
const char *cls_msg;
const char *p_msg;
const char *table = results[(i * columns) + 0];
const char *geom = results[(i * columns) + 1];
report = sqlite3_mprintf ("%s/lyr_%04d.html", output_dir, i);
tmp_table =
sqlite3_mprintf ("%s%s_%s", tmp_prefix, table, geom);
if (p_cache != NULL)
ret =
sanitize_geometry_column_r (p_cache, sqlite, table,
geom, tmp_table, report,
&n_invalids, &n_repaired,
&n_discarded, &n_failures,
err_msg);
else
ret =
sanitize_geometry_column (sqlite, table, geom,
tmp_table, report,
&n_invalids, &n_repaired,
&n_discarded, &n_failures,
err_msg);
sqlite3_free (report);
sqlite3_free (tmp_table);
fprintf (out,
"\t\t\t<tr><td align=\"center\"><a href=\"./lyr_%04d.html\">show</a></td>",
i);
fprintf (out, "<td>%s</td><td>%s</td>", table, geom);
sum_not_repaired += n_failures;
if (n_invalids == 0)
{
p_msg = "NONE: this layer was already fully valid";
cls_msg = "nil";
}
else if (n_discarded == 0 && n_failures == 0)
{
p_msg =
"NONE: this layer has been successfully sanitized and is now fully valid";
cls_msg = "ok";
}
else if (n_discarded == 0 && n_failures > 0)
{
p_msg = "Please check all discarded fragments";
cls_msg = "wng";
}
else
{
p_msg =
"Manually adjust all Geometries beyond possible repair, then retry";
cls_msg = "err";
}
if (n_repaired == 0)
cls_1 = "nil";
else
cls_1 = "ok";
fprintf (out,
"<td align=\"right\">%d</td><td class=\"%s\" align=\"right\">%d</td>",
n_invalids, cls_1, n_repaired);
if (n_discarded == 0)
cls_1 = "nil";
else
cls_1 = "wng";
if (n_failures == 0)
cls_2 = "nil";
else
cls_2 = "err";
fprintf (out,
"<td class=\"%s\" align=\"right\">%d</td><td class=\"%s\" align=\"right\">%d</td>",
cls_1, n_discarded, cls_2, n_failures);
fprintf (out, "<td class=\"%s\">%s</td></tr>\n", cls_msg,
p_msg);
}
}
sqlite3_free_table (results);
fprintf (out, "\t\t</table>\n\t</body>\n</html>\n");
fclose (out);
if (x_not_repaired != NULL)
*x_not_repaired = sum_not_repaired;
return 1;
stop:
return 0;
}
SPATIALITE_DECLARE int
sanitize_all_geometry_columns (sqlite3 * sqlite,
const char *tmp_prefix,
const char *output_dir, int *x_not_repaired,
char **err_msg)
{
return sanitize_all_geometry_columns_common (NULL, sqlite, tmp_prefix,
output_dir, x_not_repaired,
err_msg);
}
SPATIALITE_DECLARE int
sanitize_all_geometry_columns_r (const void *p_cache, sqlite3 * sqlite,
const char *tmp_prefix,
const char *output_dir, int *x_not_repaired,
char **err_msg)
{
return sanitize_all_geometry_columns_common (p_cache, sqlite, tmp_prefix,
output_dir, x_not_repaired,
err_msg);
}
#else
SPATIALITE_DECLARE int
sanitize_all_geometry_columns (sqlite3 * sqlite,
const char *tmp_prefix,
const char *output_dir, int *x_not_repaired,
char **err_msg)
{
int len;
const char *msg = "Sorry ... libspatialite was built disabling LWGEOM\n"
"and is thus unable to support MakeValid";
if (sqlite == NULL || tmp_prefix == NULL || output_dir == NULL
|| x_not_repaired == NULL)
tmp_prefix = NULL;
if (err_msg == NULL)
return 0;
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
return 0;
}
SPATIALITE_DECLARE int
sanitize_all_geometry_columns_r (const void *p_cache, sqlite3 * sqlite,
const char *tmp_prefix,
const char *output_dir, int *x_not_repaired,
char **err_msg)
{
int len;
const char *msg = "Sorry ... libspatialite was built disabling LWGEOM\n"
"and is thus unable to support MakeValid";
if (p_cache == NULL || sqlite == NULL || tmp_prefix == NULL
|| output_dir == NULL || x_not_repaired == NULL)
tmp_prefix = NULL;
if (err_msg == NULL)
return 0;
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
return 0;
}
SPATIALITE_DECLARE int
sanitize_geometry_column (sqlite3 * sqlite, const char *table, const char *geom,
const char *tmp_table, const char *report_path,
int *n_invalids, int *n_repaired, int *n_discarded,
int *n_failures, char **err_msg)
{
int len;
const char *msg = "Sorry ... libspatialite was built disabling LWGEOM\n"
"and is thus unable to support MakeValid";
if (sqlite == NULL || table == NULL || geom == NULL || tmp_table == NULL
|| report_path == NULL || n_invalids == NULL || n_repaired == NULL
|| n_discarded == NULL || n_failures == NULL)
table = NULL;
if (err_msg == NULL)
return 0;
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
return 0;
}
SPATIALITE_DECLARE int
sanitize_geometry_column_r (const void *p_cache, sqlite3 * sqlite,
const char *table, const char *geom,
const char *tmp_table, const char *report_path,
int *n_invalids, int *n_repaired, int *n_discarded,
int *n_failures, char **err_msg)
{
int len;
const char *msg = "Sorry ... libspatialite was built disabling LWGEOM\n"
"and is thus unable to support MakeValid";
if (p_cache == NULL || sqlite == NULL || table == NULL || geom == NULL
|| tmp_table == NULL || report_path == NULL || n_invalids == NULL
|| n_repaired == NULL || n_discarded == NULL || n_failures == NULL)
table = NULL;
if (err_msg == NULL)
return 0;
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
return 0;
}
#endif
#ifndef OMIT_GEOS
static struct validity_report *
alloc_validity_report (void)
{
struct validity_report *p = malloc (sizeof (struct validity_report));
p->first = NULL;
p->last = NULL;
p->n_rows = 0;
p->n_nullgeoms = 0;
p->n_valids = 0;
p->n_invalids = 0;
p->n_warnings = 0;
return p;
}
static void
free_validity_report (struct validity_report *p)
{
struct validity_report_row *r;
struct validity_report_row *rn;
r = p->first;
while (r)
{
rn = r->next;
if (r->warning != NULL)
free (r->warning);
if (r->error != NULL)
free (r->error);
if (r->extra != NULL)
free (r->extra);
free (r);
r = rn;
}
free (p);
}
static void
addMessageToValidityReport (struct validity_report *report, sqlite3_int64 rowid,
int valid, const char *error, const char *warning,
const char *extra)
{
int len;
struct validity_report_row *r =
malloc (sizeof (struct validity_report_row));
r->rowid = rowid;
r->valid = valid;
r->error = NULL;
r->warning = NULL;
r->extra = NULL;
r->next = NULL;
if (error)
{
len = strlen (error);
r->error = malloc (len + 1);
strcpy (r->error, error);
}
if (warning)
{
len = strlen (warning);
r->warning = malloc (len + 1);
strcpy (r->warning, warning);
}
if (extra)
{
len = strlen (extra);
r->extra = malloc (len + 1);
strcpy (r->extra, extra);
}
if (!valid)
report->n_invalids += 1;
else
report->n_warnings += 1;
if (report->first == NULL)
report->first = r;
if (report->last != NULL)
report->last->next = r;
report->last = r;
}
static int
check_geometry_column_common (const void *p_cache, sqlite3 * sqlite,
const char *table, const char *geom,
const char *report_path, int *n_rows,
int *n_invalids, char **err_msg)
{
char *sql;
char *xtable;
char *xgeom;
sqlite3_stmt *stmt;
int ret;
int gtype;
int srid;
const char *x_type;
const char *x_dims;
char num[256];
time_t v_time;
struct tm *v_tm;
const char *day;
const char *month;
FILE *out = NULL;
const char *p_msg;
int len;
struct validity_report_row *p_r;
struct validity_report *report = alloc_validity_report ();
if (err_msg != NULL)
*err_msg = NULL;
if (!check_table_column (sqlite, table, geom, >ype, &srid))
{
spatialite_e ("check_geometry_column error: <%s>\n"
"Not defined in \"geometry_columns\"", table);
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf ("check_geometry_column error: <%s><%s>\n"
"Not defined in \"geometry_columns\"",
table, geom);
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
goto stop;
}
switch (gtype)
{
case 0:
x_type = "GEOMETRY";
x_dims = "XY";
break;
case 1000:
x_type = "GEOMETRY";
x_dims = "XYZ";
break;
case 2000:
x_type = "GEOMETRY";
x_dims = "XYM";
break;
case 3000:
x_type = "GEOMETRY";
x_dims = "XYZM";
break;
case 1:
x_type = "POINT";
x_dims = "XY";
break;
case 1001:
x_type = "POINT";
x_dims = "XYZ";
break;
case 2001:
x_type = "POINT";
x_dims = "XYM";
break;
case 3001:
x_type = "POINT";
x_dims = "XYZM";
break;
case 2:
x_type = "LINESTRING";
x_dims = "XY";
break;
case 1002:
x_type = "LINESTRING";
x_dims = "XYZ";
break;
case 2002:
x_type = "LINESTRING";
x_dims = "XYM";
break;
case 3002:
x_type = "LINESTRING";
x_dims = "XYZM";
break;
case 3:
x_type = "POLYGON";
x_dims = "XY";
break;
case 1003:
x_type = "POLYGON";
x_dims = "XYZ";
break;
case 2003:
x_type = "POLYGON";
x_dims = "XYM";
break;
case 3003:
x_type = "POLYGON";
x_dims = "XYZM";
break;
case 4:
x_type = "MULTIPOINT";
x_dims = "XY";
break;
case 1004:
x_type = "MULTIPOINT";
x_dims = "XYZ";
break;
case 2004:
x_type = "MULTIPOINT";
x_dims = "XYM";
break;
case 3004:
x_type = "MULTIPOINT";
x_dims = "XYZM";
break;
case 5:
x_type = "MULTILINESTRING";
x_dims = "XY";
break;
case 1005:
x_type = "MULTILINESTRING";
x_dims = "XYZ";
break;
case 2005:
x_type = "MULTILINESTRING";
x_dims = "XYM";
break;
case 3005:
x_type = "MULTILINESTRING";
x_dims = "XYZM";
break;
case 6:
x_type = "MULTIPOLYGON";
x_dims = "XY";
break;
case 1006:
x_type = "MULTIPOLYGON";
x_dims = "XYZ";
break;
case 2006:
x_type = "MULTIPOLYGON";
x_dims = "XYM";
break;
case 3006:
x_type = "MULTIPOLYGON";
x_dims = "XYZM";
break;
case 7:
x_type = "GEOMETRYCOLLECTION";
x_dims = "XY";
break;
case 1007:
x_type = "GEOMETRYCOLLECTION";
x_dims = "XYZ";
break;
case 2007:
x_type = "GEOMETRYCOLLECTION";
x_dims = "XYM";
break;
case 3007:
x_type = "GEOMETRYCOLLECTION";
x_dims = "XYZM";
break;
default:
x_type = "UNKNOWN";
x_dims = "UNKNOWN";
break;
};
xtable = gaiaDoubleQuotedSql (table);
xgeom = gaiaDoubleQuotedSql (geom);
sql = sqlite3_mprintf ("SELECT ROWID, \"%s\" FROM \"%s\"", xgeom, xtable);
free (xtable);
free (xgeom);
ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt, NULL);
sqlite3_free (sql);
if (ret != SQLITE_OK)
{
spatialite_e ("check_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf ("check_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
goto stop;
}
out = fopen (report_path, "wb");
if (out == NULL)
goto stop;
while (1)
{
ret = sqlite3_step (stmt);
if (ret == SQLITE_DONE)
break;
if (ret == SQLITE_ROW)
{
gaiaGeomCollPtr geom = NULL;
sqlite3_int64 rowid = sqlite3_column_int (stmt, 0);
report->n_rows += 1;
if (sqlite3_column_type (stmt, 1) == SQLITE_BLOB)
{
const unsigned char *blob = sqlite3_column_blob (stmt, 1);
int n_bytes = sqlite3_column_bytes (stmt, 1);
geom = gaiaFromSpatiaLiteBlobWkb (blob, n_bytes);
}
if (geom)
{
int valid;
const char *error;
const char *warning;
const char *extra;
if (p_cache != NULL)
{
gaiaResetGeosMsg_r (p_cache);
valid = gaiaIsValid_r (p_cache, geom);
error = gaiaGetGeosErrorMsg_r (p_cache);
warning = gaiaGetGeosWarningMsg_r (p_cache);
extra = gaiaGetGeosAuxErrorMsg_r (p_cache);
}
else
{
gaiaResetGeosMsg ();
valid = gaiaIsValid (geom);
error = gaiaGetGeosErrorMsg ();
warning = gaiaGetGeosWarningMsg ();
extra = gaiaGetGeosAuxErrorMsg ();
}
if (!valid || error || warning)
addMessageToValidityReport (report, rowid, valid,
error, warning, extra);
else
report->n_valids += 1;
gaiaFreeGeomColl (geom);
}
else
report->n_nullgeoms += 1;
}
else
{
spatialite_e ("check_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
if (err_msg != NULL)
{
char *msg =
sqlite3_mprintf
("check_geometry_column error: <%s>\n",
sqlite3_errmsg (sqlite));
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
sqlite3_free (msg);
}
break;
}
}
sqlite3_finalize (stmt);
fprintf (out,
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
fprintf (out, "<html>\n\t<head>\n");
fprintf (out,
"\t\t<meta content=\"text/html; charset=UTF-8\" http-equiv=\"content-type\">\n");
fprintf (out, "\t\t<title>SpatiaLite Validity Check - Table: %s</title>\n",
table);
fprintf (out, "\t\t<style type=\"text/css\">\n");
fprintf (out, "\t\t\th1 {color:red;}\n");
fprintf (out, "\t\t\th2 {color:navy;}\n");
fprintf (out, "\t\t\ttd.title {background-color:silver;}\n");
fprintf (out, "\t\t\ttd.ok {background-color:#00ff00;}\n");
fprintf (out, "\t\t\ttd.err {background-color:#ff0000;}\n");
fprintf (out, "\t\t\ttd.wng {background-color:#ffff00;}\n");
fprintf (out, "\t\t</style>\n");
fprintf (out, "\t</head>\n\t<body bgcolor=\"#f8fff8\">\n");
time (&v_time);
v_tm = localtime (&v_time);
switch (v_tm->tm_wday)
{
case 0:
day = "Sun";
break;
case 1:
day = "Mon";
break;
case 2:
day = "Tue";
break;
case 3:
day = "Wed";
break;
case 4:
day = "Thu";
break;
case 5:
day = "Fri";
break;
case 6:
day = "Sat";
break;
};
switch (v_tm->tm_mon)
{
case 0:
month = "Jan";
break;
case 1:
month = "Feb";
break;
case 2:
month = "Mar";
break;
case 3:
month = "Apr";
break;
case 4:
month = "May";
break;
case 5:
month = "Jun";
break;
case 6:
month = "Jul";
break;
case 7:
month = "Aug";
break;
case 8:
month = "Sep";
break;
case 9:
month = "Oct";
break;
case 10:
month = "Nov";
break;
case 11:
month = "Dec";
break;
};
fprintf (out, "\t\t%d-%s-%d, %s [%02d:%02d:%02d]<br>\n",
v_tm->tm_year + 1900, month, v_tm->tm_mday, day, v_tm->tm_hour,
v_tm->tm_min, v_tm->tm_sec);
fprintf (out, "\t\t<h1>SpatiaLite Validity Check</h1>\n");
fprintf (out, "\t\t<h2>Summary</h2>\n");
fprintf (out,
"\t\t<table cellspacing=\"4\" callpadding=\"4\" border=\"1\">\n");
fprintf (out,
"\t\t\t<tr><td class=\"title\" colspan=\"2\" align=\"center\">Table / Layer</td></tr>\n");
fprintf (out, "\t\t\t<tr><td>Table</td><td>%s</td></tr>\n", table);
fprintf (out, "\t\t\t<tr><td>Geometry Column</td><td>%s</td></tr>\n", geom);
fprintf (out, "\t\t\t<tr><td>Geometry Type</td><td>%s</td></tr>\n", x_type);
fprintf (out, "\t\t\t<tr><td>Dimensions</td><td>%s</td></tr>\n", x_dims);
fprintf (out, "\t\t\t<tr><td>SRID</td><td align=\"right\">%d</td></tr>\n",
srid);
fprintf (out,
"\t\t\t<tr><td class=\"title\" colspan=\"2\" align=\"center\">Statistics</td></tr>\n");
fprintf (out,
"\t\t\t<tr><td>Total Rows</td><td align=\"right\">%d</td></tr>\n",
report->n_rows);
if (report->n_nullgeoms > 0)
fprintf (out,
"\t\t\t<tr><td>NULL Geometries</td><td class=\"wng\" align=\"right\">%d</td></tr>\n",
report->n_nullgeoms);
else
fprintf (out,
"\t\t\t<tr><td>NULL Geometries</td><td align=\"right\">NONE</td></tr>\n");
fprintf (out,
"\t\t\t<tr><td>Valid Geometries (full valid)</td><td class=\"ok\" align=\"right\">%d</td></tr>\n",
report->n_valids);
if (report->n_warnings > 0)
fprintf (out,
"\t\t\t<tr><td>Valid Geometries (minor issues)</td><td class=\"wng\" align=\"right\">%d</td></tr>\n",
report->n_warnings);
else
fprintf (out,
"\t\t\t<tr><td>Valid Geometries (minor issues)</td><td align=\"right\">NONE</td></tr>\n");
if (report->n_invalids > 0)
fprintf (out,
"\t\t\t<tr><td>Invalid Geometries</td><td class=\"err\" align=\"right\">%d</td></tr>\n",
report->n_invalids);
else
fprintf (out,
"\t\t\t<tr><td>Invalid Geometries</td><td align=\"right\">NONE</td></tr>\n");
fprintf (out,
"\t\t\t<tr><td class=\"title\" colspan=\"2\" align=\"center\">Suggested Action</td></tr>\n");
if (report->n_invalids > 0)
{
fprintf (out,
"\t\t\t<tr><td colspan=\"2\" class=\"err\">This layer contains invalid Geometries;<br>");
fprintf (out, "a repair action is urgently required.</td></tr>\n");
}
else if (report->n_warnings > 0)
{
fprintf (out,
"\t\t\t<tr><td colspan=\"2\" class=\"wng\">This layer contains valid but dubious Geometries;<br>");
fprintf (out, "a repair action is suggested.</td></tr>\n");
}
else
{
fprintf (out,
"\t\t\t<tr><td colspan=\"2\" class=\"ok\">This layer is perfectly valid;<br>");
fprintf (out, "doesn't require any corrective action.</td></tr>\n");
}
fprintf (out, "\t\t</table>\n");
if (report->n_invalids > 0)
{
fprintf (out, "\t\t\t<hr>\n\t\t<h2>Invalid Geometries List</h2>\n");
fprintf (out,
"\t\t<table cellspacing=\"4\" callpadding=\"4\" border=\"1\">\n");
fprintf (out,
"\t\t\t<tr><td class=\"title\" align=\"center\">ROWID</td>");
fprintf (out,
"<td class=\"title\" align=\"center\">Error Cause</td></tr>\n");
p_r = report->first;
while (p_r)
{
if (p_r->valid != 0)
{
p_r = p_r->next;
continue;
}
sprintf (num, FRMT64, p_r->rowid);
p_msg = "Unknown cause";
if (p_r->error)
p_msg = p_r->error;
else if (p_r->warning)
p_msg = p_r->warning;
else if (p_r->extra)
p_msg = p_r->extra;
fprintf (out,
"\t\t\t<tr><td align=\"right\">%s</td><td>%s</td></tr>\n",
num, p_msg);
p_r = p_r->next;
}
fprintf (out, "\t\t</table>\n");
}
if (report->n_warnings > 0)
{
fprintf (out,
"\t\t\t<hr>\n\t\t<h2>Valid Geometries List (anyway presenting some minor issue)</h2>\n");
fprintf (out,
"\t\t<table cellspacing=\"4\" callpadding=\"4\" border=\"1\">\n");
fprintf (out,
"\t\t\t<tr><td class=\"title\" align=\"center\">ROWID</td>");
fprintf (out,
"<td class=\"title\" align=\"center\">Warning Cause</td></tr>\n");
p_r = report->first;
while (p_r)
{
if (p_r->valid != 1)
{
p_r = p_r->next;
continue;
}
sprintf (num, FRMT64, p_r->rowid);
p_msg = "Unknown cause";
if (p_r->error)
p_msg = p_r->error;
else if (p_r->warning)
p_msg = p_r->warning;
fprintf (out,
"\t\t\t<tr><td align=\"right\">%s</td><td>%s</td></tr>\n",
num, p_msg);
p_r = p_r->next;
}
fprintf (out, "\t\t</table>\n");
}
fprintf (out, "\t</body>\n</html>\n");
fclose (out);
if (n_rows != NULL)
*n_rows = report->n_rows;
if (n_invalids != NULL)
*n_invalids = report->n_invalids;
free_validity_report (report);
return 1;
stop:
free_validity_report (report);
if (out)
fclose (out);
return 0;
}
SPATIALITE_DECLARE int
check_geometry_column (sqlite3 * sqlite, const char *table, const char *geom,
const char *report_path, int *n_rows, int *n_invalids,
char **err_msg)
{
return check_geometry_column_common (NULL, sqlite, table, geom, report_path,
n_rows, n_invalids, err_msg);
}
SPATIALITE_DECLARE int
check_geometry_column_r (const void *p_cache, sqlite3 * sqlite,
const char *table, const char *geom,
const char *report_path, int *n_rows, int *n_invalids,
char **err_msg)
{
return check_geometry_column_common (p_cache, sqlite, table, geom,
report_path, n_rows, n_invalids,
err_msg);
}
static int
check_all_geometry_columns_common (const void *p_cache, sqlite3 * sqlite,
const char *output_dir, int *x_invalids,
char **err_msg)
{
const char *sql;
int ret;
int i;
char **results;
int rows;
int columns;
int n_rows;
int n_invalids;
char *report;
FILE *out = NULL;
time_t v_time;
struct tm *v_tm;
const char *day;
const char *month;
int sum_invalids = 0;
#if defined(_WIN32)
_mkdir (output_dir);
#else
mkdir (output_dir, 0777);
#endif
if (err_msg != NULL)
*err_msg = NULL;
report = sqlite3_mprintf ("%s/index.html", output_dir);
out = fopen (report, "wb");
sqlite3_free (report);
if (out == NULL)
goto stop;
fprintf (out,
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
fprintf (out, "<html>\n\t<head>\n");
fprintf (out,
"\t\t<meta content=\"text/html; charset=UTF-8\" http-equiv=\"content-type\">\n");
fprintf (out,
"\t\t<title>SpatiaLite Validity Check - All Tables</title>\n");
fprintf (out, "\t\t<style type=\"text/css\">\n");
fprintf (out, "\t\t\th1 {color:navy;}\n");
fprintf (out, "\t\t\ttd.title {background-color:silver;}\n");
fprintf (out, "\t\t\ttd.ok {background-color:#00ff00;}\n");
fprintf (out, "\t\t\ttd.err {background-color:#ff0000;}\n");
fprintf (out, "\t\t</style>\n");
fprintf (out, "\t</head>\n\t<body bgcolor=\"#f8fff8\">\n");
time (&v_time);
v_tm = localtime (&v_time);
switch (v_tm->tm_wday)
{
case 0:
day = "Sun";
break;
case 1:
day = "Mon";
break;
case 2:
day = "Tue";
break;
case 3:
day = "Wed";
break;
case 4:
day = "Thu";
break;
case 5:
day = "Fri";
break;
case 6:
day = "Sat";
break;
};
switch (v_tm->tm_mon)
{
case 0:
month = "Jan";
break;
case 1:
month = "Feb";
break;
case 2:
month = "Mar";
break;
case 3:
month = "Apr";
break;
case 4:
month = "May";
break;
case 5:
month = "Jun";
break;
case 6:
month = "Jul";
break;
case 7:
month = "Aug";
break;
case 8:
month = "Sep";
break;
case 9:
month = "Oct";
break;
case 10:
month = "Nov";
break;
case 11:
month = "Dec";
break;
};
fprintf (out, "\t\t%d-%s-%d, %s [%02d:%02d:%02d]<br>\n",
v_tm->tm_year + 1900, month, v_tm->tm_mday, day, v_tm->tm_hour,
v_tm->tm_min, v_tm->tm_sec);
fprintf (out, "\t\t<h1>SpatiaLite Validity Check</h1>\n");
fprintf (out,
"\t\t<table cellspacing=\"4\" callpadding=\"4\" border=\"1\">\n");
fprintf (out,
"\t\t\t<tr><td class=\"title\" align=\"center\">Show Details</td>");
fprintf (out, "<td class=\"title\" align=\"center\">Table</td>");
fprintf (out, "<td class=\"title\" align=\"center\">Geometry</td>");
fprintf (out, "<td class=\"title\" align=\"center\">Total Rows</td>");
fprintf (out,
"<td class=\"title\" align=\"center\">Invalid Geometries</td>");
fprintf (out,
"<td class=\"title\" align=\"center\">Suggested Action</td></tr>\n");
sql = "SELECT f_table_name, f_geometry_column FROM geometry_columns";
ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
if (ret != SQLITE_OK)
goto stop;
if (rows < 1)
;
else
{
for (i = 1; i <= rows; i++)
{
const char *table = results[(i * columns) + 0];
const char *geom = results[(i * columns) + 1];
report = sqlite3_mprintf ("%s/lyr_%04d.html", output_dir, i);
if (p_cache != NULL)
ret =
check_geometry_column_r (p_cache, sqlite, table, geom,
report, &n_rows, &n_invalids,
err_msg);
else
ret =
check_geometry_column (sqlite, table, geom, report,
&n_rows, &n_invalids, err_msg);
sqlite3_free (report);
fprintf (out,
"\t\t\t<tr><td align=\"center\"><a href=\"./lyr_%04d.html\">show</a></td>",
i);
fprintf (out, "<td>%s</td><td>%s</td>", table, geom);
sum_invalids += n_invalids;
if (n_invalids == 0)
{
fprintf (out,
"<td align=\"right\">%d</td><td class=\"ok\" align=\"right\">%d</td>",
n_rows, n_invalids);
fprintf (out,
"<td class=\"ok\">NONE: this layer is fully valid</td></tr>\n");
}
else
{
fprintf (out,
"<td align=\"right\">%d</td><td class=\"err\" align=\"right\">%d</td>",
n_rows, n_invalids);
fprintf (out,
"<td class=\"err\">Repairing this layer is urgently required</td></tr>\n");
}
}
}
sqlite3_free_table (results);
fprintf (out, "\t\t</table>\n\t</body>\n</html>\n");
fclose (out);
if (x_invalids != NULL)
*x_invalids = sum_invalids;
return 1;
stop:
return 0;
}
SPATIALITE_DECLARE int
check_all_geometry_columns (sqlite3 * sqlite,
const char *output_dir, int *x_invalids,
char **err_msg)
{
return check_all_geometry_columns_common (NULL, sqlite, output_dir,
x_invalids, err_msg);
}
SPATIALITE_DECLARE int
check_all_geometry_columns_r (const void *p_cache, sqlite3 * sqlite,
const char *output_dir, int *x_invalids,
char **err_msg)
{
return check_all_geometry_columns_common (p_cache, sqlite, output_dir,
x_invalids, err_msg);
}
#else
SPATIALITE_DECLARE int
check_all_geometry_columns (sqlite3 * sqlite,
const char *output_dir, int *x_invalids,
char **err_msg)
{
int len;
const char *msg = "Sorry ... libspatialite was built disabling LWGEOM\n"
"and is thus unable to support IsValid";
if (sqlite == NULL || output_dir == NULL || x_invalids == NULL)
output_dir = NULL;
if (err_msg == NULL)
return 0;
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
return 0;
}
SPATIALITE_DECLARE int
check_all_geometry_columns_r (const void *p_cache, sqlite3 * sqlite,
const char *output_dir, int *x_invalids,
char **err_msg)
{
int len;
const char *msg = "Sorry ... libspatialite was built disabling LWGEOM\n"
"and is thus unable to support IsValid";
if (p_cache == NULL || sqlite == NULL || output_dir == NULL
|| x_invalids == NULL)
output_dir = NULL;
if (err_msg == NULL)
return 0;
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
return 0;
}
SPATIALITE_DECLARE int
check_geometry_column (sqlite3 * sqlite,
const char *table,
const char *geom,
const char *report_path,
int *n_rows, int *n_invalids, char **err_msg)
{
int len;
const char *msg = "Sorry ... libspatialite was built disabling GEOS\n"
"and is thus unable to support IsValid";
if (sqlite == NULL || table == NULL || geom == NULL ||
report_path == NULL || n_rows == NULL || n_invalids == NULL)
table = NULL;
if (err_msg == NULL)
return 0;
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
return 0;
}
SPATIALITE_DECLARE int
check_geometry_column_r (const void *p_cache, sqlite3 * sqlite,
const char *table,
const char *geom,
const char *report_path,
int *n_rows, int *n_invalids, char **err_msg)
{
int len;
const char *msg = "Sorry ... libspatialite was built disabling GEOS\n"
"and is thus unable to support IsValid";
if (p_cache == NULL || sqlite == NULL || table == NULL || geom == NULL ||
report_path == NULL || n_rows == NULL || n_invalids == NULL)
table = NULL;
if (err_msg == NULL)
return 0;
len = strlen (msg);
*err_msg = malloc (len + 1);
strcpy (*err_msg, msg);
return 0;
}
#endif