Merge pull request #39 from evanmiller/mdb-queries

Add ancient mdb-queries tool by Leonard Leblanc
This commit is contained in:
Evan Miller
2020-09-01 22:55:58 -04:00
committed by GitHub
4 changed files with 290 additions and 1 deletions

View File

@@ -177,4 +177,5 @@ script:
- ./src/util/mdb-ver test/data/ASampleDatabase.accdb - ./src/util/mdb-ver test/data/ASampleDatabase.accdb
- ./src/util/mdb-ver test/data/nwind.mdb - ./src/util/mdb-ver test/data/nwind.mdb
- ./src/util/mdb-sql -i test/sql/nwind.sql test/data/nwind.mdb - ./src/util/mdb-sql -i test/sql/nwind.sql test/data/nwind.mdb
- ./src/util/mdb-queries test/data/ASampleDatabase.accdb qryCostsSummedByOwner
- env MDBPATH=test/data ./src/odbc/unittest - env MDBPATH=test/data ./src/odbc/unittest

View File

@@ -25,6 +25,7 @@ the 0.7/0.8 days:
- [x] GLib is now optional - [x] GLib is now optional
- [x] Improved ODBC compliance - [x] Improved ODBC compliance
- [x] Continuous integration with Travis and AppVeyor - [x] Continuous integration with Travis and AppVeyor
- [x] New `mdb-queries` tool
The rest of this README explains what you can find in the project, how to The rest of this README explains what you can find in the project, how to
install it, and how to contribute. install it, and how to contribute.
@@ -55,6 +56,7 @@ Provides command line utilities, including:
| `mdb-header` | Generates a C header to be used in exporting mdb data to a C prog. | | `mdb-header` | Generates a C header to be used in exporting mdb data to a C prog. |
| `mdb-parsecsv` | Generates a C program given a CSV file made with mdb-export. | | `mdb-parsecsv` | Generates a C program given a CSV file made with mdb-export. |
| `mdb-sql` | A simple SQL engine (also used by ODBC and gmdb). | | `mdb-sql` | A simple SQL engine (also used by ODBC and gmdb). |
| `mdb-queries` | List and print queries stored in the database. |
| `prcat` | Prints the catalog table from an mdb file. | | `prcat` | Prints the catalog table from an mdb file. |
| `prkkd` | Dump of information about design view data given the offset to it. | | `prkkd` | Dump of information about design view data given the offset to it. |
| `prtable` | Dump of a table definition. | | `prtable` | Dump of a table definition. |

View File

@@ -1,6 +1,6 @@
AUTOMAKE_OPTIONS = subdir-objects AUTOMAKE_OPTIONS = subdir-objects
SUBDIRS = bash-completion SUBDIRS = bash-completion
bin_PROGRAMS = mdb-export mdb-array mdb-schema mdb-tables mdb-parsecsv mdb-header mdb-sql mdb-ver mdb-prop mdb-count bin_PROGRAMS = mdb-export mdb-array mdb-schema mdb-tables mdb-parsecsv mdb-header mdb-sql mdb-ver mdb-prop mdb-count mdb-queries
noinst_PROGRAMS = mdb-import prtable prcat prdata prkkd prdump prole updrow prindex noinst_PROGRAMS = mdb-import prtable prcat prdata prkkd prdump prole updrow prindex
mdb_export_SOURCES = mdb-export.c mdb_export_SOURCES = mdb-export.c
mdb_schema_SOURCES = mdb-schema.c mdb_schema_SOURCES = mdb-schema.c
@@ -8,6 +8,7 @@ mdb_tables_SOURCES = mdb-tables.c
mdb_sql_SOURCES = mdb-sql.c mdb_sql_SOURCES = mdb-sql.c
mdb_ver_SOURCES = mdb-ver.c mdb_ver_SOURCES = mdb-ver.c
mdb_import_SOURCES = mdb-import.c mdb_import_SOURCES = mdb-import.c
mdb_queries_SOURCES = mdb-queries.c
updrow_SOURCES = updrow.c updrow_SOURCES = updrow.c
LIBS = $(GLIB_LIBS) @LIBS@ LIBS = $(GLIB_LIBS) @LIBS@
DEFS = @DEFS@ -DLOCALEDIR=\"$(localedir)\" DEFS = @DEFS@ -DLOCALEDIR=\"$(localedir)\"

285
src/util/mdb-queries.c Normal file
View File

@@ -0,0 +1,285 @@
/* MDB Tools - A library for reading MS Access database file
* Copyright (C) 2000 Brian Bruns
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**************************************************************
This utility allows you to list the queries in the database
and dump the SQL associated with a specific query.
The idea behind this utility is to eventually allow the
results to be piped to mdb-sql allowing a (fairly) simple
method to execute queries that are stored in the access
database.
created by Leonard Leblanc <lleblanc@macroelite.ca>
(with much help from the other mdb utilities)
Modified by Evan Miller and added to repository 2020
**************************************************************/
#include "mdbtools.h"
#undef MDB_BIND_SIZE
#define MDB_BIND_SIZE 200000
void mdb_list_queries(MdbHandle *mdb, int line_break, char *delimiter);
char * mdb_get_query_id(MdbHandle *mdb,char *query);
int main (int argc, char **argv) {
unsigned int i;
MdbHandle *mdb = NULL;
MdbCatalogEntry *entry = NULL, *sys_queries = NULL, *temp = NULL;
MdbTableDef *table = NULL;
char *delimiter = NULL;
int list_only=0;
int found_match=0;
int line_break=0;
int opt;
char *query_id;
// variables for the msysqueries table. hopefully 256 is big enough
char *attribute = (char *) malloc(MDB_BIND_SIZE);
char *expression = (char *) malloc(MDB_BIND_SIZE);
char *flag = (char *) malloc(MDB_BIND_SIZE);
char *name1 = (char *) malloc(MDB_BIND_SIZE);
char *name2 = (char *) malloc(MDB_BIND_SIZE);
char *objectid = (char *) malloc(MDB_BIND_SIZE);
char *order = (char *) malloc(MDB_BIND_SIZE);
//variables for the generation of sql
char *sql_tables = (char *) malloc(MDB_BIND_SIZE);
char *sql_columns = (char *) malloc(MDB_BIND_SIZE);
char *sql_where = (char *) malloc(MDB_BIND_SIZE);
char *sql_sorting = (char *) malloc(MDB_BIND_SIZE);
/* see getopt(3) for more information on getopt and this will become clear */
while ((opt=getopt(argc, argv, "L1d:"))!=-1) {
switch (opt) {
case 'L':
list_only = 1;
break;
case '1':
line_break = 1;
break;
case 'd':
delimiter = (char *) malloc(strlen(optarg)+1);
strcpy(delimiter, optarg);
break;
}
}
/* we've parsed all the options and we should at least have a database name left */
if ((argc - optind) < 1) {
fprintf (stderr, "Usage: %s [options] <database filename> <query name>\n",argv[0]);
fprintf (stderr, "where options are:\n");
fprintf (stderr, " -L\t\t\tList queries in the database (default if no query name is passed)\n");
fprintf (stderr, " -1\t\t\tUse newline as the delimiter (used in conjuction with listing)\n");
fprintf (stderr, " -d <delimiter>\tSpecify delimiter to use\n");
exit (1);
}
/* let's turn list_only on if only a database filename was passed */
if((argc-optind) < 2)
list_only=1;
/* open the database */
if (!(mdb = mdb_open(argv[optind],MDB_NOFLAGS))) {
fprintf(stderr,"Couldn't open database.\n");
exit(1);
}
/* read the catalog */
if (!mdb_read_catalog (mdb, MDB_ANY)) {
fprintf(stderr,"File does not appear to be an Access database\n");
exit(1);
}
if(list_only) {
mdb_list_queries(mdb,line_break,delimiter);
} else {
/* let's get the entry for the user specified query
we also want to get the catalog for the MSysQueries table
while we are here */
for (i=0; i < mdb->num_catalog; i++) {
temp = g_ptr_array_index(mdb->catalog, i);
if(strcmp(temp->object_name,argv[optind+1]) == 0) {
entry = g_ptr_array_index(mdb->catalog,i);
found_match=1;
} else if(strcmp(temp->object_name,"MSysQueries") == 0) {
sys_queries = g_ptr_array_index(mdb->catalog,i);
}
}
if(found_match) {
/* Let's get the id for the query */
query_id = mdb_get_query_id(mdb,entry->object_name);
table = mdb_read_table(sys_queries);
if(table) {
mdb_read_columns(table);
mdb_bind_column_by_name(table, "Attribute", attribute, NULL);
mdb_bind_column_by_name(table, "Expression", expression, NULL);
mdb_bind_column_by_name(table, "Flag", flag, NULL);
mdb_bind_column_by_name(table, "Name1", name1, NULL);
mdb_bind_column_by_name(table, "Name2", name2, NULL);
mdb_bind_column_by_name(table, "ObjectId", objectid, NULL);
mdb_bind_column_by_name(table, "Order", order, NULL);
mdb_rewind_table(table);
while (mdb_fetch_row(table)) {
if(strcmp(query_id,objectid) == 0) {
//we have a row for our query
switch(atoi(attribute)) {
case 5: // table name
if(strcmp(sql_tables,"") == 0) {
strcpy(sql_tables,name1);
} else {
strcat(sql_tables,",");
strcat(sql_tables,name1);
}
break;
case 6: // column name
if(strcmp(sql_columns,"") == 0) {
strcpy(sql_columns,expression);
} else {
strcat(sql_columns,",");
strcat(sql_columns,expression);
}
break;
case 7: // join/relationship where clause
//fprintf(stdout,"join tables: %s - %s\n",name1,name2);
//fprintf(stdout,"join clause: %s\n",expression);
break;
case 8: // where clause
strcpy(sql_where,expression);
break;
case 11: // sorting
if(strcmp(sql_sorting,"") == 0) {
strcpy(sql_sorting,"ORDER BY ");
strcat(sql_sorting,expression);
if(strcmp(name1,"D") == 0) {
strcat(sql_sorting," DESCENDING");
}
}
break;
}
}
}
/*fprintf(stdout,"sql_tables: %s\n",sql_tables);
fprintf(stdout,"sql_columns: %s\n",sql_columns);
fprintf(stdout,"sql_where: %s\n",sql_where);
fprintf(stdout,"sql_sorting: %s\n",sql_sorting);*/
/* print out the sql statement */
if(strcmp(sql_where,"") == 0) {
fprintf(stdout,"SELECT %s FROM %s %s\n",sql_columns,sql_tables,sql_sorting);
} else {
fprintf(stdout,"SELECT %s FROM %s WHERE %s %s\n",sql_columns,sql_tables,sql_where,sql_sorting);
}
mdb_free_tabledef(table);
}
} else {
fprintf(stderr,"Couldn't locate the specified query: %s\n",argv[optind+1]);
}
}
mdb_close(mdb);
if(delimiter) free(delimiter);
exit(0);
}
/****************************************************
mdb_list_queries
Description: This function prints the list of queries to stdout
Parameters: MdbHandle *mdb (handle for the current database)
int line_break (whether or not to place a line break between each query)
char *delimiter (delimiter when not using a line break)
Returns: nothing
****************************************************/
void mdb_list_queries(MdbHandle *mdb, int line_break, char *delimiter) {
unsigned int i;
MdbCatalogEntry *entry;
/* loop over each entry in the catalog */
for (i=0; i < mdb->num_catalog; i++) {
entry = g_ptr_array_index(mdb->catalog, i);
/* if it's a query */
if (entry->object_type == MDB_QUERY) {
if (line_break)
fprintf (stdout, "%s\n", entry->object_name);
else if (delimiter)
fprintf (stdout, "%s%s", entry->object_name, delimiter);
else
fprintf (stdout, "%s ", entry->object_name);
}
}
if (!line_break)
fprintf (stdout, "\n");
}
/****************************************************
mdb_get_query_id
Description: This function returns the id of the passed query
Parameters: MdbHandle *mdb (handle for the current database)
char *query (name of the desired query to retrieve)
Returns: char * (id of the current query)
****************************************************/
char * mdb_get_query_id(MdbHandle *mdb, char *query) {
unsigned int i;
MdbCatalogEntry *entry = NULL;
MdbTableDef *table = NULL;
static char id[256];
char name[256];
/* loop over each entry in the catalog */
for (i=0; i < mdb->num_catalog; i++) {
entry = g_ptr_array_index(mdb->catalog, i);
if(strcmp(entry->object_name,"MSysObjects") == 0) {
break;
}
}
table = mdb_read_table(entry);
if(table) {
mdb_read_columns(table);
mdb_bind_column_by_name(table, "Id", id, NULL);
mdb_bind_column_by_name(table, "Name", name, NULL);
mdb_rewind_table(table);
while (mdb_fetch_row(table)) {
if(strcmp(query,name) == 0) {
break;
}
}
mdb_free_tabledef(table);
}
return id;
}