write_ogr.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. /*!
  2. \file lib/vector/Vlib/write_ogr.c
  3. \brief Vector library - write vector feature (OGR format)
  4. Higher level functions for reading/writing/manipulating vectors.
  5. Inspired by v.out.ogr's code.
  6. \todo OGR version of V2__delete_area_cats_from_cidx_nat()
  7. \todo function to delete corresponding entry in fidx
  8. \todo OGR version of V2__add_area_cats_to_cidx_nat
  9. \todo OGR version of V2__add_line_to_topo_nat
  10. (C) 2009-2011 by the GRASS Development Team
  11. This program is free software under the GNU General Public License
  12. (>=v2). Read the file COPYING that comes with GRASS for details.
  13. \author Martin Landa <landa.martin gmail.com>
  14. */
  15. #include <grass/vector.h>
  16. #include <grass/dbmi.h>
  17. #include <grass/glocale.h>
  18. #ifdef HAVE_OGR
  19. #include <ogr_api.h>
  20. static int sqltype_to_ogrtype(int);
  21. static int write_attributes(dbDriver *, int, const struct field_info *,
  22. OGRLayerH, OGRFeatureH);
  23. static void V2__add_line_to_topo_ogr(struct Map_info *Map, int line,
  24. const struct line_pnts *points,
  25. const struct line_cats *cats)
  26. {
  27. int first, s, i;
  28. int type, area, side;
  29. struct Plus_head *plus;
  30. struct P_line *Line;
  31. struct bound_box box, abox;
  32. G_debug(3, "V2__add_line_to_topo_ogr(): line = %d", line);
  33. plus = &(Map->plus);
  34. Line = plus->Line[line];
  35. type = Line->type;
  36. if (plus->built >= GV_BUILD_AREAS &&
  37. type == GV_BOUNDARY) {
  38. struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
  39. if (topo->N1 != topo->N2) {
  40. G_warning(_("Boundary is not closed. Skipping."));
  41. return;
  42. }
  43. /* Build new areas/isles */
  44. for (s = 0; s < 2; s++) {
  45. side = (s == 0 ? GV_LEFT : GV_RIGHT);
  46. area = Vect_build_line_area(Map, line, side);
  47. if (area > 0) { /* area */
  48. Vect_get_area_box(Map, area, &box);
  49. if (first) {
  50. Vect_box_copy(&abox, &box);
  51. first = FALSE;
  52. }
  53. else
  54. Vect_box_extend(&abox, &box);
  55. }
  56. else if (area < 0) {
  57. /* isle -> must be attached -> add to abox */
  58. Vect_get_isle_box(Map, -area, &box);
  59. if (first) {
  60. Vect_box_copy(&abox, &box);
  61. first = FALSE;
  62. }
  63. else
  64. Vect_box_extend(&abox, &box);
  65. }
  66. G_debug(4, "Vect_build_line_area(): -> area = %d", area);
  67. }
  68. /* Attach centroid/isle to the new area */
  69. if (plus->built >= GV_BUILD_ATTACH_ISLES)
  70. Vect_attach_isles(Map, &abox);
  71. if (plus->built >= GV_BUILD_CENTROIDS)
  72. Vect_attach_centroids(Map, &abox);
  73. }
  74. /* Add category index */
  75. for (i = 0; i < cats->n_cats; i++) {
  76. dig_cidx_add_cat_sorted(plus, cats->field[i], cats->cat[i], line,
  77. type);
  78. }
  79. return;
  80. }
  81. #endif
  82. /*!
  83. \brief Writes feature on level 1 (OGR interface)
  84. Note:
  85. - centroids are not supported in OGR, pseudotopo holds virtual
  86. centroids
  87. - boundaries are not supported in OGR, pseudotopo treats polygons
  88. as boundaries
  89. \todo How to deal with OGRNullFID ?
  90. \param Map pointer to Map_info structure
  91. \param type feature type
  92. \param points pointer to line_pnts structure (feature geometry)
  93. \param cats pointer to line_cats structure (feature categories)
  94. \return feature offset into file
  95. \return -1 on error
  96. */
  97. off_t V1_write_line_ogr(struct Map_info *Map, int type,
  98. const struct line_pnts *points,
  99. const struct line_cats *cats)
  100. {
  101. #ifdef HAVE_OGR
  102. int i, cat, ret;
  103. struct field_info *Fi;
  104. struct Format_info_ogr *fInfo;
  105. off_t offset;
  106. OGRGeometryH Ogr_geometry;
  107. OGRFeatureH Ogr_feature;
  108. OGRFeatureDefnH Ogr_featuredefn;
  109. OGRwkbGeometryType Ogr_geom_type;
  110. if (!Map->fInfo.ogr.layer) {
  111. /* create OGR layer if doesn't exist */
  112. if (V2_open_new_ogr(Map, type) < 0)
  113. return -1;
  114. }
  115. cat = -1; /* no attributes to be written */
  116. if (cats->n_cats > 0 && Vect_get_num_dblinks(Map) > 0) {
  117. /* check for attributes */
  118. Fi = Vect_get_dblink(Map, 0);
  119. if (Fi) {
  120. if (!Vect_cat_get(cats, Fi->number, &cat))
  121. G_warning(_("No category defined for layer %d"), Fi->number);
  122. if (cats->n_cats > 1) {
  123. G_warning(_("Feature has more categories, using "
  124. "category %d (from layer %d)"),
  125. cat, cats->field[0]);
  126. }
  127. }
  128. }
  129. fInfo = &(Map->fInfo.ogr);
  130. Ogr_featuredefn = OGR_L_GetLayerDefn(fInfo->layer);
  131. Ogr_geom_type = OGR_FD_GetGeomType(Ogr_featuredefn);
  132. /* determine matching OGR feature geometry type */
  133. if (type & (GV_POINT | GV_KERNEL)) {
  134. if (Ogr_geom_type != wkbPoint &&
  135. Ogr_geom_type != wkbPoint25D) {
  136. G_warning(_("Feature is not a point. Skipping."));
  137. return -1;
  138. }
  139. Ogr_geometry = OGR_G_CreateGeometry(wkbPoint);
  140. }
  141. else if (type & GV_LINE) {
  142. if (Ogr_geom_type != wkbLineString &&
  143. Ogr_geom_type != wkbLineString25D) {
  144. G_warning(_("Feature is not a line. Skipping."));
  145. return -1;
  146. }
  147. Ogr_geometry = OGR_G_CreateGeometry(wkbLineString);
  148. }
  149. else if (type & GV_BOUNDARY) {
  150. if (Ogr_geom_type != wkbPolygon) {
  151. G_warning(_("Feature is not a polygon. Skipping."));
  152. return -1;
  153. }
  154. Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon);
  155. }
  156. else if (type & GV_FACE) {
  157. if (Ogr_geom_type != wkbPolygon25D) {
  158. G_warning(_("Feature is not a face. Skipping."));
  159. return -1;
  160. }
  161. Ogr_geometry = OGR_G_CreateGeometry(wkbPolygon25D);
  162. }
  163. else {
  164. G_warning(_("Unsupported feature type (%d)"), type);
  165. return -1;
  166. }
  167. G_debug(3, "V1_write_line_ogr(): type = %d", type);
  168. if (Ogr_geom_type == wkbPolygon || Ogr_geom_type == wkbPolygon25D) {
  169. /* create exterior ring */
  170. OGRGeometryH Ogr_ring;
  171. int npoints;
  172. npoints = points->n_points - 1;
  173. Ogr_ring = OGR_G_CreateGeometry(wkbLinearRing);
  174. if (points->x[0] != points->x[npoints] ||
  175. points->y[0] != points->y[npoints] ||
  176. points->z[0] != points->z[npoints]) {
  177. G_warning(_("Boundary is not closed. Skipping."));
  178. return -1;
  179. }
  180. /* add points */
  181. for (i = 0; i < points->n_points; i++) {
  182. OGR_G_AddPoint(Ogr_ring, points->x[i], points->y[i],
  183. points->z[i]);
  184. }
  185. OGR_G_AddGeometry(Ogr_geometry, Ogr_ring);
  186. }
  187. else {
  188. for (i = 0; i < points->n_points; i++) {
  189. OGR_G_AddPoint(Ogr_geometry, points->x[i], points->y[i],
  190. points->z[i]);
  191. }
  192. }
  193. G_debug(4, " n_points = %d", points->n_points);
  194. /* create feature & set geometry */
  195. Ogr_feature = OGR_F_Create(Ogr_featuredefn);
  196. OGR_F_SetGeometry(Ogr_feature, Ogr_geometry);
  197. /* write attributes */
  198. if (cat > -1 && fInfo->dbdriver) {
  199. write_attributes(fInfo->dbdriver,
  200. cat, Fi, fInfo->layer, Ogr_feature);
  201. G_free(Fi);
  202. }
  203. /* write feature into layer */
  204. ret = OGR_L_CreateFeature(fInfo->layer, Ogr_feature);
  205. /* update offset array */
  206. if (fInfo->offset_num >= fInfo->offset_alloc) {
  207. fInfo->offset_alloc += 1000;
  208. fInfo->offset = (int *) G_realloc(fInfo->offset,
  209. fInfo->offset_alloc *
  210. sizeof(int));
  211. }
  212. offset = fInfo->offset_num;
  213. fInfo->offset[fInfo->offset_num++] = (int) OGR_F_GetFID(Ogr_feature);
  214. if (Ogr_geom_type == wkbPolygon || Ogr_geom_type == wkbPolygon25D) {
  215. /* register exterior ring in offset array */
  216. fInfo->offset[fInfo->offset_num++] = 0;
  217. }
  218. /* destroy */
  219. OGR_G_DestroyGeometry(Ogr_geometry);
  220. OGR_F_Destroy(Ogr_feature);
  221. if (ret != OGRERR_NONE)
  222. return -1;
  223. G_debug(3, "V1_write_line_ogr(): -> offset = %lu", (unsigned long) offset);
  224. return offset;
  225. #else
  226. G_fatal_error(_("GRASS is not compiled with OGR support"));
  227. return -1;
  228. #endif
  229. }
  230. /*!
  231. \brief Writes feature on level 2
  232. \param Map pointer to Map_info structure
  233. \param type feature type
  234. \param points pointer to line_pnts structure (feature geometry)
  235. \param cats pointer to line_cats structure (feature categories)
  236. \return feature offset into file
  237. \return -1 on error
  238. */
  239. off_t V2_write_line_ogr(struct Map_info *Map, int type,
  240. const struct line_pnts *points, const struct line_cats *cats)
  241. {
  242. #ifdef HAVE_OGR
  243. int line;
  244. off_t offset;
  245. struct Plus_head *plus;
  246. struct bound_box box;
  247. line = 0;
  248. plus = &(Map->plus);
  249. G_debug(3, "V2_write_line_ogr()");
  250. offset = V1_write_line_ogr(Map, type, points, cats);
  251. if (offset < 0)
  252. return -1;
  253. /* Update topology */
  254. if (plus->built >= GV_BUILD_BASE) {
  255. dig_line_box(points, &box);
  256. line = dig_add_line(plus, type, points, &box, offset);
  257. G_debug(3, "\tline added to topo with line = %d", line);
  258. if (line == 1)
  259. Vect_box_copy(&(plus->box), &box);
  260. else
  261. Vect_box_extend(&(plus->box), &box);
  262. if (type == GV_BOUNDARY) {
  263. int ret, cline;
  264. long FID;
  265. double x, y;
  266. struct bound_box box;
  267. struct line_pnts *CPoints;
  268. /* add virtual centroid to pseudo-topology */
  269. ret = Vect_get_point_in_poly(points, &x, &y);
  270. if (ret == 0) {
  271. CPoints = Vect_new_line_struct();
  272. Vect_append_point(CPoints, x, y, 0.0);
  273. FID = Map->fInfo.ogr.offset[offset];
  274. dig_line_box(CPoints, &box);
  275. cline = dig_add_line(plus, GV_CENTROID,
  276. CPoints, &box, FID);
  277. G_debug(4, "\tCentroid: x = %f, y = %f, cat = %lu, line = %d",
  278. x, y, FID, cline);
  279. dig_cidx_add_cat(plus, 1, (int) FID,
  280. cline, GV_CENTROID);
  281. Vect_destroy_line_struct(CPoints);
  282. }
  283. else {
  284. G_warning(_("Unable to calculate centroid for area"));
  285. }
  286. }
  287. V2__add_line_to_topo_ogr(Map, line, points, cats);
  288. }
  289. G_debug(3, "updated lines : %d , updated nodes : %d", plus->uplist.n_uplines,
  290. plus->uplist.n_upnodes);
  291. /* returns int line, but is defined as off_t for compatibility with
  292. * Write_line_array in write.c */
  293. return line;
  294. #else
  295. G_fatal_error(_("GRASS is not compiled with OGR support"));
  296. return -1;
  297. #endif
  298. }
  299. /*!
  300. \brief Rewrites feature at the given offset (level 1)
  301. \param Map pointer to Map_info structure
  302. \param offset feature offset
  303. \param type feature type
  304. \param points feature geometry
  305. \param cats feature categories
  306. \return feature offset (rewriten feature)
  307. \return -1 on error
  308. */
  309. off_t V1_rewrite_line_ogr(struct Map_info *Map,
  310. int line,
  311. int type,
  312. off_t offset,
  313. const struct line_pnts *points, const struct line_cats *cats)
  314. {
  315. #ifdef HAVE_OGR
  316. if (type != V1_read_line_ogr(Map, NULL, NULL, offset)) {
  317. G_warning(_("Unable to rewrite feature (incompatible feature types)"));
  318. return -1;
  319. }
  320. /* delete old */
  321. V1_delete_line_ogr(Map, offset);
  322. return V1_write_line_ogr(Map, type, points, cats);
  323. #else
  324. G_fatal_error(_("GRASS is not compiled with OGR support"));
  325. return -1;
  326. #endif
  327. }
  328. /*!
  329. \brief Rewrites feature to 'coor' file (topology level) - internal use only
  330. \param Map pointer to Map_info structure
  331. \param line feature id
  332. \param type feature type
  333. \param offset unused
  334. \param points feature geometry
  335. \param cats feature categories
  336. \return offset where line was rewritten
  337. \return -1 on error
  338. */
  339. off_t V2_rewrite_line_ogr(struct Map_info *Map, int line, int type, off_t offset,
  340. const struct line_pnts *points, const struct line_cats *cats)
  341. {
  342. #ifdef HAVE_OGR
  343. if (type != V2_read_line_ogr(Map, NULL, NULL, line)) {
  344. G_warning(_("Unable to rewrite feature (incompatible feature types)"));
  345. return -1;
  346. }
  347. V2_delete_line_ogr(Map, line);
  348. return V2_write_line_ogr(Map, type, points, cats);
  349. #else
  350. G_fatal_error(_("GRASS is not compiled with OGR support"));
  351. return -1;
  352. #endif
  353. }
  354. /*!
  355. \brief Deletes feature at the given offset (level 1)
  356. \param Map pointer Map_info structure
  357. \param offset feature offset
  358. \return 0 on success
  359. \return -1 on error
  360. */
  361. int V1_delete_line_ogr(struct Map_info *Map, off_t offset)
  362. {
  363. #ifdef HAVE_OGR
  364. G_debug(3, "V1_delete_line_ogr(), offset = %lu", (unsigned long) offset);
  365. if (!Map->fInfo.ogr.layer) {
  366. G_warning(_("OGR layer not defined"));
  367. return -1;
  368. }
  369. if (offset >= Map->fInfo.ogr.offset_num)
  370. return -1;
  371. if (OGR_L_DeleteFeature(Map->fInfo.ogr.layer, Map->fInfo.ogr.offset[offset]) != OGRERR_NONE)
  372. return -1;
  373. return 0;
  374. #else
  375. G_fatal_error(_("GRASS is not compiled with OGR support"));
  376. return -1;
  377. #endif
  378. }
  379. /*!
  380. \brief Deletes feature (topology level) -- internal use only
  381. \param pointer to Map_info structure
  382. \param line feature id
  383. \return 0 on success
  384. \return -1 on error
  385. */
  386. int V2_delete_line_ogr(struct Map_info *Map, int line)
  387. {
  388. #ifdef HAVE_OGR
  389. int ret, i, type, first;
  390. struct P_line *Line;
  391. struct Plus_head *plus;
  392. static struct line_cats *Cats = NULL;
  393. static struct line_pnts *Points = NULL;
  394. G_debug(3, "V2_delete_line_ogr(), line = %d", line);
  395. type = first = 0;
  396. Line = NULL;
  397. plus = &(Map->plus);
  398. if (plus->built >= GV_BUILD_BASE) {
  399. Line = Map->plus.Line[line];
  400. if (Line == NULL)
  401. G_fatal_error(_("Attempt to delete dead feature"));
  402. type = Line->type;
  403. }
  404. if (!Cats) {
  405. Cats = Vect_new_cats_struct();
  406. }
  407. if (!Points) {
  408. Points = Vect_new_line_struct();
  409. }
  410. type = V2_read_line_ogr(Map, Points, Cats, line);
  411. /* Update category index */
  412. if (plus->update_cidx) {
  413. for (i = 0; i < Cats->n_cats; i++) {
  414. dig_cidx_del_cat(plus, Cats->field[i], Cats->cat[i], line, type);
  415. }
  416. }
  417. /* Update fidx */
  418. /* delete the line from coor */
  419. ret = V1_delete_line_ogr(Map, Line->offset);
  420. if (ret == -1) {
  421. return ret;
  422. }
  423. /* Update topology */
  424. if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
  425. /* TODO */
  426. /* remove centroid together with boundary (is really an OGR polygon) */
  427. }
  428. /* Delete reference from area */
  429. if (plus->built >= GV_BUILD_CENTROIDS && type == GV_CENTROID) {
  430. /* for OGR mapsets, virtual centroid will be removed when polygon is removed */
  431. }
  432. /* delete the line from topo */
  433. dig_del_line(plus, line, Points->x[0], Points->y[0], Points->z[0]);
  434. /* Rebuild areas/isles and attach centroids and isles */
  435. if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY) {
  436. /* maybe not needed VERIFY */
  437. }
  438. return ret;
  439. #else
  440. G_fatal_error(_("GRASS is not compiled with OGR support"));
  441. return -1;
  442. #endif
  443. }
  444. #ifdef HAVE_OGR
  445. int write_attributes(dbDriver *driver, int cat, const struct field_info *Fi,
  446. OGRLayerH Ogr_layer, OGRFeatureH Ogr_feature)
  447. {
  448. int j, ogrfieldnum;
  449. char buf[2000];
  450. int ncol, sqltype, ctype, ogrtype, more;
  451. const char *fidcol, *colname;
  452. dbTable *table;
  453. dbString dbstring;
  454. dbColumn *column;
  455. dbCursor cursor;
  456. dbValue *value;
  457. OGRFieldDefnH hFieldDefn;
  458. G_debug(3, "write_attributes(): cat = %d", cat);
  459. if (cat < 0) {
  460. G_warning(_("Feature without category of layer %d"), Fi->number);
  461. return 0;
  462. }
  463. db_init_string(&dbstring);
  464. /* read & set attributes */
  465. sprintf(buf, "SELECT * FROM %s WHERE %s = %d", Fi->table, Fi->key,
  466. cat);
  467. G_debug(4, "SQL: %s", buf);
  468. db_set_string(&dbstring, buf);
  469. /* select data */
  470. if (db_open_select_cursor(driver, &dbstring, &cursor, DB_SEQUENTIAL) != DB_OK) {
  471. G_fatal_error(_("Unable to select attributes for category %d"),
  472. cat);
  473. }
  474. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
  475. G_fatal_error(_("Unable to fetch data from table <%s>"),
  476. Fi->table);
  477. }
  478. if (!more) {
  479. G_warning(_("No database record for category %d, "
  480. "no attributes will be written"),
  481. cat);
  482. return -1;
  483. }
  484. fidcol = OGR_L_GetFIDColumn(Ogr_layer);
  485. table = db_get_cursor_table(&cursor);
  486. ncol = db_get_table_number_of_columns(table);
  487. for (j = 0; j < ncol; j++) {
  488. column = db_get_table_column(table, j);
  489. colname = db_get_column_name(column);
  490. if (fidcol && *fidcol && strcmp(colname, fidcol) == 0) {
  491. /* skip fid column */
  492. continue;
  493. }
  494. value = db_get_column_value(column);
  495. /* for debug only */
  496. db_convert_column_value_to_string(column, &dbstring);
  497. G_debug(2, "col %d : val = %s", j,
  498. db_get_string(&dbstring));
  499. sqltype = db_get_column_sqltype(column);
  500. ctype = db_sqltype_to_Ctype(sqltype);
  501. ogrtype = sqltype_to_ogrtype(sqltype);
  502. G_debug(2, " colctype = %d", ctype);
  503. ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, colname);
  504. if (ogrfieldnum < 0) {
  505. /* create field if not exists */
  506. hFieldDefn = OGR_Fld_Create(colname, ogrtype);
  507. if (OGR_L_CreateField(Ogr_layer, hFieldDefn, TRUE) != OGRERR_NONE)
  508. G_warning(_("Unable to create field <%s>"), colname);
  509. ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, colname);
  510. }
  511. /* Reset */
  512. OGR_F_UnsetField(Ogr_feature, ogrfieldnum);
  513. /* prevent writing NULL values */
  514. if (!db_test_value_isnull(value)) {
  515. switch (ctype) {
  516. case DB_C_TYPE_INT:
  517. OGR_F_SetFieldInteger(Ogr_feature, ogrfieldnum,
  518. db_get_value_int(value));
  519. break;
  520. case DB_C_TYPE_DOUBLE:
  521. OGR_F_SetFieldDouble(Ogr_feature, ogrfieldnum,
  522. db_get_value_double(value));
  523. break;
  524. case DB_C_TYPE_STRING:
  525. OGR_F_SetFieldString(Ogr_feature, ogrfieldnum,
  526. db_get_value_string(value));
  527. break;
  528. case DB_C_TYPE_DATETIME:
  529. db_convert_column_value_to_string(column,
  530. &dbstring);
  531. OGR_F_SetFieldString(Ogr_feature, ogrfieldnum,
  532. db_get_string(&dbstring));
  533. break;
  534. }
  535. }
  536. }
  537. db_close_cursor (&cursor);
  538. db_free_string(&dbstring);
  539. return 1;
  540. }
  541. int sqltype_to_ogrtype(int sqltype)
  542. {
  543. int ctype, ogrtype;
  544. ctype = db_sqltype_to_Ctype(sqltype);
  545. switch(ctype) {
  546. case DB_C_TYPE_INT:
  547. ogrtype = OFTInteger;
  548. break;
  549. case DB_C_TYPE_DOUBLE:
  550. ogrtype = OFTReal;
  551. break;
  552. case DB_C_TYPE_STRING:
  553. ogrtype = OFTString;
  554. break;
  555. case DB_C_TYPE_DATETIME:
  556. ogrtype = OFTString;
  557. break;
  558. default:
  559. ogrtype = OFTString;
  560. break;
  561. }
  562. return ogrtype;
  563. }
  564. #endif /* HAVE_OGR */