1 /*
2
3 GeoPackage extensions for SpatiaLite / SQLite
4
5 Version: MPL 1.1/GPL 2.0/LGPL 2.1
6
7 The contents of this file are subject to the Mozilla Public License Version
8 1.1 (the "License"); you may not use this file except in compliance with
9 the License. You may obtain a copy of the License at
10 http://www.mozilla.org/MPL/
11
12 Software distributed under the License is distributed on an "AS IS" basis,
13 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 for the specific language governing rights and limitations under the
15 License.
16
17 The Original Code is GeoPackage Extensions
18
19 The Initial Developer of the Original Code is Brad Hards (bradh@frogmouth.net)
20
21 Portions created by the Initial Developer are Copyright (C) 2012-2015
22 the Initial Developer. All Rights Reserved.
23
24 Contributor(s):
25
26 Alternatively, the contents of this file may be used under the terms of
27 either the GNU General Public License Version 2 or later (the "GPL"), or
28 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 in which case the provisions of the GPL or the LGPL are applicable instead
30 of those above. If you wish to allow use of your version of this file only
31 under the terms of either the GPL or the LGPL, and not to allow others to
32 use your version of this file under the terms of the MPL, indicate your
33 decision by deleting the provisions above and replace them with the notice
34 and other provisions required by the GPL or the LGPL. If you do not delete
35 the provisions above, a recipient may use your version of this file under
36 the terms of any one of the MPL, the GPL or the LGPL.
37
38 */
39
40 #include "spatialite/geopackage.h"
41 #include "geopackage_internal.h"
42
43 #if defined(_WIN32) && !defined(__MINGW32__)
44 #include "config-msvc.h"
45 #else
46 #include "config.h"
47 #endif
48
49 #ifdef ENABLE_GEOPACKAGE
50 GEOPACKAGE_PRIVATE void
fnct_gpkgGetNormalRow(sqlite3_context * context,int argc,sqlite3_value ** argv)51 fnct_gpkgGetNormalRow (sqlite3_context * context, int argc,
52 sqlite3_value ** argv)
53 {
54 /* SQL function:
55 / gpkgGetNormalRow(tile_table_name, normal_zoom_level, inverted_row_number)
56 /
57 / Gets the normal integer row number for the specified table, normal zoom level
58 / and inverted row number. Raises a SQL exception if no zoom level row record in
59 / tile_matrix_metadata
60 /
61 / Note that this function can also be used to convert from a normal row number
62 / to an inverted row number - this conversion is symmetric.
63 */
64 const unsigned char *table;
65 int zoom_level;
66 int inverted_row_number;
67 int matrix_height;
68 int normal_row_number;
69 char *sql_stmt = NULL;
70 sqlite3 *sqlite = NULL;
71 char *errMsg = NULL;
72 char **results;
73 char *endptr = 0;
74 int rows = 0;
75 int columns = 0;
76 int ret = 0;
77
78 if (argc == 0)
79 argc = 0; /* suppressing stupid compiler warnings */
80
81 if (sqlite3_value_type (argv[0]) != SQLITE_TEXT)
82 {
83 sqlite3_result_error (context,
84 "gpkgGetNormalRow() error: argument 1 [tile_table_name] is not of the String type",
85 -1);
86 return;
87 }
88 table = sqlite3_value_text (argv[0]);
89
90 if (sqlite3_value_type (argv[1]) != SQLITE_INTEGER)
91 {
92 sqlite3_result_error (context,
93 "gpkgGetNormalRow() error: argument 2 [normal zoom level] is not of the integer type",
94 -1);
95 return;
96 }
97 zoom_level = sqlite3_value_int (argv[1]);
98
99 if (sqlite3_value_type (argv[2]) != SQLITE_INTEGER)
100 {
101 sqlite3_result_error (context,
102 "gpkgGetNormalRow() error: argument 3 [inverted_row_number] is not of the integer type",
103 -1);
104 return;
105 }
106 inverted_row_number = sqlite3_value_int (argv[2]);
107
108 sql_stmt =
109 sqlite3_mprintf
110 ("SELECT matrix_height FROM gpkg_tile_matrix WHERE table_name = %Q AND zoom_level=%i",
111 table, zoom_level);
112
113 sqlite = sqlite3_context_db_handle (context);
114 ret = sqlite3_get_table (sqlite,
115 sql_stmt, &results, &rows, &columns, &errMsg);
116 sqlite3_free (sql_stmt);
117 if (ret != SQLITE_OK)
118 {
119 sqlite3_result_error (context, errMsg, -1);
120 sqlite3_free (errMsg);
121 return;
122 }
123 if (rows != 1)
124 {
125 sqlite3_result_error (context,
126 "gpkgGetNormalRow: tile table or zoom level not found",
127 -1);
128 sqlite3_free_table (results);
129 sqlite3_free (errMsg);
130 return;
131 }
132 errno = 0;
133 matrix_height = strtol (results[1 * columns + 0], &endptr, 10);
134 if ((endptr == results[1 * columns + 0])
135 || (matrix_height < 0)
136 || (errno == ERANGE
137 && matrix_height == INT_MAX) || (errno != 0 && matrix_height == 0))
138 {
139 sqlite3_free_table (results);
140 sqlite3_result_error (context,
141 "gpkgGetNormalRow: could not parse result (corrupt GeoPackage?)",
142 -1);
143 return;
144 }
145 sqlite3_free_table (results);
146 if ((inverted_row_number >= matrix_height) || (inverted_row_number < 0))
147 {
148 sqlite3_result_error (context,
149 "gpkgGetNormalRow: row number outside of matrix height range",
150 -1);
151 return;
152 }
153
154 normal_row_number = matrix_height - inverted_row_number - 1;
155 sqlite3_result_int (context, normal_row_number);
156 }
157 #endif
158