1 /* MDB Tools - A library for reading MS Access database files
2  * Copyright (C) 2000 Brian Bruns
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19 
20 #ifdef JAVA
21 #include "javadefines.h"
22 #define MdbBackendType_STRUCT_ELEMENT(a,b,c,d) new MdbBackendType(a,b,c,d)
23 #else
24 #define MdbBackendType_STRUCT_ELEMENT(a,b,c,d) {a,b,c,d}
25 /*
26 ** functions to deal with different backend database engines
27 */
28 #
29 #include "mdbtools.h"
30 
31 #ifdef DMALLOC
32 #include "dmalloc.h"
33 #endif
34 
35 #endif   /* JAVA */
36 
37 static int is_init;
38 GHashTable *mdb_backends;
39 
40    /*    Access data types */
41 static MdbBackendType mdb_access_types[] = {
42 		MdbBackendType_STRUCT_ELEMENT("Unknown 0x00", 0,0,0),
43 		MdbBackendType_STRUCT_ELEMENT("Boolean", 0,0,0),
44 		MdbBackendType_STRUCT_ELEMENT("Byte", 0,0,0),
45 		MdbBackendType_STRUCT_ELEMENT("Integer", 0,0,0),
46 		MdbBackendType_STRUCT_ELEMENT("Long Integer", 0,0,0),
47 		MdbBackendType_STRUCT_ELEMENT("Currency", 0,0,0),
48 		MdbBackendType_STRUCT_ELEMENT("Single", 0,0,0),
49 		MdbBackendType_STRUCT_ELEMENT("Double", 0,0,0),
50 		MdbBackendType_STRUCT_ELEMENT("DateTime (Short)", 0,0,1),
51 		MdbBackendType_STRUCT_ELEMENT("Unknown 0x09", 0,0,0),
52 		MdbBackendType_STRUCT_ELEMENT("Text", 1,0,1),
53 		MdbBackendType_STRUCT_ELEMENT("OLE", 1,0,1),
54 		MdbBackendType_STRUCT_ELEMENT("Memo/Hyperlink",1,0,1),
55 		MdbBackendType_STRUCT_ELEMENT("Unknown 0x0d",0,0,0),
56 		MdbBackendType_STRUCT_ELEMENT("Unknown 0x0e",0,0,0),
57 		MdbBackendType_STRUCT_ELEMENT("Replication ID",0,0,0),
58 		MdbBackendType_STRUCT_ELEMENT("Numeric",1,1,0)
59 };
60 
61 /*    Oracle data types */
62 static MdbBackendType mdb_oracle_types[] = {
63 		MdbBackendType_STRUCT_ELEMENT("Oracle_Unknown 0x00",0,0,0),
64 		MdbBackendType_STRUCT_ELEMENT("NUMBER",1,0,0),
65 		MdbBackendType_STRUCT_ELEMENT("NUMBER",1,0,0),
66 		MdbBackendType_STRUCT_ELEMENT("NUMBER",1,0,0),
67 		MdbBackendType_STRUCT_ELEMENT("NUMBER",1,0,0),
68 		MdbBackendType_STRUCT_ELEMENT("NUMBER",1,0,0),
69 		MdbBackendType_STRUCT_ELEMENT("FLOAT",0,0,0),
70 		MdbBackendType_STRUCT_ELEMENT("FLOAT",0,0,0),
71 		MdbBackendType_STRUCT_ELEMENT("DATE",0,0,0),
72 		MdbBackendType_STRUCT_ELEMENT("Oracle_Unknown 0x09",0,0,0),
73 		MdbBackendType_STRUCT_ELEMENT("VARCHAR2",1,0,1),
74 		MdbBackendType_STRUCT_ELEMENT("BLOB",1,0,1),
75 		MdbBackendType_STRUCT_ELEMENT("CLOB",1,0,1),
76 		MdbBackendType_STRUCT_ELEMENT("Oracle_Unknown 0x0d",0,0,0),
77 		MdbBackendType_STRUCT_ELEMENT("Oracle_Unknown 0x0e",0,0,0),
78 		MdbBackendType_STRUCT_ELEMENT("NUMBER",1,0,0),
79 		MdbBackendType_STRUCT_ELEMENT("NUMBER",1,0,0),
80 };
81 
82 /*    Sybase/MSSQL data types */
83 static MdbBackendType mdb_sybase_types[] = {
84 		MdbBackendType_STRUCT_ELEMENT("Sybase_Unknown 0x00",0,0,0),
85 		MdbBackendType_STRUCT_ELEMENT("bit",0,0,0),
86 		MdbBackendType_STRUCT_ELEMENT("char",1,0,1),
87 		MdbBackendType_STRUCT_ELEMENT("smallint",0,0,0),
88 		MdbBackendType_STRUCT_ELEMENT("int",0,0,0),
89 		MdbBackendType_STRUCT_ELEMENT("money",0,0,0),
90 		MdbBackendType_STRUCT_ELEMENT("real",0,0,0),
91 		MdbBackendType_STRUCT_ELEMENT("float",0,0,0),
92 		MdbBackendType_STRUCT_ELEMENT("smalldatetime",0,0,0),
93 		MdbBackendType_STRUCT_ELEMENT("Sybase_Unknown 0x09",0,0,0),
94 		MdbBackendType_STRUCT_ELEMENT("varchar",1,0,1),
95 		MdbBackendType_STRUCT_ELEMENT("varbinary",1,0,1),
96 		MdbBackendType_STRUCT_ELEMENT("text",1,0,1),
97 		MdbBackendType_STRUCT_ELEMENT("Sybase_Unknown 0x0d",0,0,0),
98 		MdbBackendType_STRUCT_ELEMENT("Sybase_Unknown 0x0e",0,0,0),
99 		MdbBackendType_STRUCT_ELEMENT("Sybase_Replication ID",0,0,0),
100 		MdbBackendType_STRUCT_ELEMENT("numeric",1,1,0),
101 };
102 
103 /*    Postgres data types */
104 static MdbBackendType mdb_postgres_types[] = {
105 		MdbBackendType_STRUCT_ELEMENT("Postgres_Unknown 0x00",0,0,0),
106 		MdbBackendType_STRUCT_ELEMENT("Bool",0,0,0),
107 		MdbBackendType_STRUCT_ELEMENT("Int2",0,0,0),
108 		MdbBackendType_STRUCT_ELEMENT("Int4",0,0,0),
109 		MdbBackendType_STRUCT_ELEMENT("Int8",0,0,0),
110 		MdbBackendType_STRUCT_ELEMENT("Money",0,0,0),
111 		MdbBackendType_STRUCT_ELEMENT("Float4",0,0,0),
112 		MdbBackendType_STRUCT_ELEMENT("Float8",0,0,0),
113 		MdbBackendType_STRUCT_ELEMENT("Timestamp",0,0,0),
114 		MdbBackendType_STRUCT_ELEMENT("Postgres_Unknown 0x09",0,0,0),
115 		MdbBackendType_STRUCT_ELEMENT("Char",1,0,1),
116 		MdbBackendType_STRUCT_ELEMENT("Postgres_Unknown 0x0b",0,0,0),
117 		MdbBackendType_STRUCT_ELEMENT("Postgres_Unknown 0x0c",0,0,0),
118 		MdbBackendType_STRUCT_ELEMENT("Postgres_Unknown 0x0d",0,0,0),
119 		MdbBackendType_STRUCT_ELEMENT("Postgres_Unknown 0x0e",0,0,0),
120 		MdbBackendType_STRUCT_ELEMENT("Serial",0,0,0),
121 		MdbBackendType_STRUCT_ELEMENT("Postgres_Unknown 0x10",0,0,0),
122 };
123 /*    MySQL data types */
124 static MdbBackendType mdb_mysql_types[] = {
125 		MdbBackendType_STRUCT_ELEMENT("Text",1,0,1),
126 		MdbBackendType_STRUCT_ELEMENT("char",0,0,0),
127 		MdbBackendType_STRUCT_ELEMENT("int",0,0,0),
128 		MdbBackendType_STRUCT_ELEMENT("int",0,0,0),
129 		MdbBackendType_STRUCT_ELEMENT("int",0,0,0),
130 		MdbBackendType_STRUCT_ELEMENT("float",0,0,0),
131 		MdbBackendType_STRUCT_ELEMENT("float",0,0,0),
132 		MdbBackendType_STRUCT_ELEMENT("float",0,0,0),
133 		MdbBackendType_STRUCT_ELEMENT("date",0,0,1),
134 		MdbBackendType_STRUCT_ELEMENT("varchar",1,0,1),
135 		MdbBackendType_STRUCT_ELEMENT("varchar",1,0,1),
136 		MdbBackendType_STRUCT_ELEMENT("varchar",1,0,1),
137 		MdbBackendType_STRUCT_ELEMENT("text",1,0,1),
138 		MdbBackendType_STRUCT_ELEMENT("blob",0,0,0),
139 		MdbBackendType_STRUCT_ELEMENT("text",1,0,1),
140 		MdbBackendType_STRUCT_ELEMENT("numeric",1,1,0),
141 		MdbBackendType_STRUCT_ELEMENT("numeric",1,1,0),
142 };
143 #ifndef JAVA
144 static gboolean mdb_drop_backend(gpointer key, gpointer value, gpointer data);
145 
146 char *mdb_get_coltype_string(MdbBackend *backend, int col_type)
147 {
148 	static char buf[16];
149 
150 	if (col_type > 0x10 ) {
151    		// return NULL;
152 		snprintf(buf,sizeof(buf), "type %04x", col_type);
153 		return buf;
154 	} else {
155 		return backend->types_table[col_type].name;
156 	}
157 }
158 
159 int mdb_coltype_takes_length(MdbBackend *backend, int col_type)
160 {
161 	return backend->types_table[col_type].needs_length;
162 }
163 
164 /**
165  * mdb_init_backends
166  *
167  * Initializes the mdb_backends hash and loads the builtin backends.
168  * Use mdb_remove_backends() to destroy this hash when done.
169  */
170 void mdb_init_backends()
171 {
172 	mdb_backends = g_hash_table_new(g_str_hash, g_str_equal);
173 
174 	mdb_register_backend(mdb_access_types, "access");
175 	mdb_register_backend(mdb_sybase_types, "sybase");
176 	mdb_register_backend(mdb_oracle_types, "oracle");
177 	mdb_register_backend(mdb_postgres_types, "postgres");
178 	mdb_register_backend(mdb_mysql_types, "mysql");
179 }
180 void mdb_register_backend(MdbBackendType *backend_type, char *backend_name)
181 {
182 	MdbBackend *backend = (MdbBackend *) g_malloc0(sizeof(MdbBackend));
183 	backend->types_table = backend_type;
184 	g_hash_table_insert(mdb_backends, backend_name, backend);
185 }
186 
187 /**
188  * mdb_remove_backends
189  *
190  * Removes all entries from and destroys the mdb_backends hash.
191  */
192 void mdb_remove_backends()
193 {
194 	g_hash_table_foreach_remove(mdb_backends, mdb_drop_backend, NULL);
195 	g_hash_table_destroy(mdb_backends);
196 }
197 static gboolean mdb_drop_backend(gpointer key, gpointer value, gpointer data)
198 {
199 	MdbBackend *backend = (MdbBackend *)value;
200 	g_free (backend);
201 	return TRUE;
202 }
203 
204 /**
205  * mdb_set_default_backend
206  * @mdb: Handle to open MDB database file
207  * @backend_name: Name of the backend to set as default
208  *
209  * Sets the default backend of the handle @mdb to @backend_name.
210  *
211  * Returns: 1 if successful, 0 if unsuccessful.
212  */
213 int mdb_set_default_backend(MdbHandle *mdb, char *backend_name)
214 {
215 	MdbBackend *backend;
216 
217 	backend = (MdbBackend *) g_hash_table_lookup(mdb_backends, backend_name);
218 	if (backend) {
219 		mdb->default_backend = backend;
220 		mdb->backend_name = (char *) g_strdup(backend_name);
221 		is_init = 0;
222 		return 1;
223 	} else {
224 		return 0;
225 	}
226 }
227 
228 /**
229  * mdb_get_relationships
230  * @mdb: Handle to open MDB database file
231  *
232  * Generates relationships by reading the MSysRelationships table.
233  *   'szColumn' contains the column name of the child table.
234  *   'szObject' contains the table name of the child table.
235  *   'szReferencedColumn' contains the column name of the parent table.
236  *   'szReferencedObject' contains the table name of the parent table.
237  *
238  * Returns: a string stating that relationships are not supported for the
239  *   selected backend, or a string containing SQL commands for setting up
240  *   the relationship, tailored for the selected backend.  The caller is
241  *   responsible for freeing this string.
242  */
243 char *mdb_get_relationships(MdbHandle *mdb)
244 {
245 	unsigned int i;
246 	gchar *text = NULL;  /* String to be returned */
247 	static char *bound[4];  /* Bound values */
248 	static MdbTableDef *table;  /* Relationships table */
249 	int backend = 0;  /* Backends: 1=oracle */
250 
251 	if (strncmp(mdb->backend_name,"oracle",6) == 0) {
252 		backend = 1;
253 	} else {
254 		if (is_init == 0) { /* the first time through */
255 			is_init = 1;
256 			return (char *) g_strconcat(
257 				"-- relationships are not supported for ",
258 				mdb->backend_name, NULL);
259 		} else { /* the second time through */
260 			is_init = 0;
261 			return NULL;
262 		}
263 	}
264 
265 	if (is_init == 0) {
266 		table = mdb_read_table_by_name(mdb, "MSysRelationships", MDB_TABLE);
267 		if ((!table) || (table->num_rows == 0)) {
268 			return NULL;
269 		}
270 
271 		mdb_read_columns(table);
272 		for (i=0;i<4;i++) {
273 			bound[i] = (char *) g_malloc0(MDB_BIND_SIZE);
274 		}
275 		mdb_bind_column_by_name(table, "szColumn", bound[0], NULL);
276 		mdb_bind_column_by_name(table, "szObject", bound[1], NULL);
277 		mdb_bind_column_by_name(table, "szReferencedColumn", bound[2], NULL);
278 		mdb_bind_column_by_name(table, "szReferencedObject", bound[3], NULL);
279 		mdb_rewind_table(table);
280 
281 		is_init = 1;
282 	}
283 	else if (table->cur_row >= table->num_rows) {  /* past the last row */
284 		for (i=0;i<4;i++)
285 			g_free(bound[i]);
286 		is_init = 0;
287 		return NULL;
288 	}
289 
290 	if (!mdb_fetch_row(table)) {
291 		for (i=0;i<4;i++)
292 			g_free(bound[i]);
293 		is_init = 0;
294 		return NULL;
295 	}
296 
297 	switch (backend) {
298 	  case 1:  /* oracle */
299 		text = g_strconcat("alter table ", bound[1],
300 			" add constraint ", bound[3], "_", bound[1],
301 			" foreign key (", bound[0], ")"
302 			" references ", bound[3], "(", bound[2], ")", NULL);
303 		break;
304 	}
305 
306 	return (char *)text;
307 }
308 #endif
309