/*
**	relshow.c	- Display the database structure
**
**
** Copyright (c) 1993-95  David J. Hughes
** Copyright (c) 1995  Hughes Technologies Pty Ltd
**
** Permission to use, copy, and distribute for non-commercial purposes,
** is hereby granted without fee, providing that the above copyright
** notice appear in all copies and that both the copyright notice and this
** permission notice appear in supporting documentation.
**
** This software is provided "as is" without any expressed or implied warranty.
**
** ID = "$Id:"
**
*/



#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#ifdef WIN32
#  include <winsock.h>
#endif

#include <common/portability.h>
#include "msql_priv.h"
#include "msql.h"


char	PROGNAME[] = "Relshow";

void usage()
{
	printf("\nUsage : relshow [-h host] [-f conf] [dbName [relName] [index | _seq]]\n\n");
	printf("         Where   dbName is the name of a database\n");
	printf("                 relname is the name of a relation\n");
	printf("                 index is the name of an index \n");
	printf("                 _seq is the sequence system variable\n");
	printf("\n");
	printf("If no database is given, list the known databases\n");
	printf("If no relation is given, list relations in the database\n");
	printf("If database and relation given, list fields ");
	printf("in the given relation\n");
	printf("If database, relation and index are given, list the ");
	printf("details of the index\n");
	printf("If database, relation and _seq are given, show ");
	printf("details of the table sequence\n");
	printf("\n\007");
}




int main(argc,argv)
	int	argc;
	char	*argv[];
{
	char	dbShow = 0,
		relShow = 0,
		fieldShow = 0,
		indexShow = 0,
		seqShow = 0,
		*idxType;
	char	typeName[10];
	int	sock,
		argsLeft,
		errFlag = 0,
		c;
	m_row	cur;
	m_result *res;
	m_field	*curField;
        char    *host = NULL,
		*confFile = NULL;
        extern  int optind;
        extern  char *optarg;
#ifdef WIN32
	WORD	wVersion;
	WSADATA	wsaData;
#endif


        while((c=getopt(argc,argv,"f:h:"))!= -1)
        {
                switch(c)
                {
                        case 'h':
                                if (host)
                                        errFlag++;
                                else
                                        host = optarg;
                                break;

                        case 'f':
                                if (confFile)
                                        errFlag++;
                                else
                                        confFile = optarg;
                                break;

                        case '?':
                                errFlag++;
                                break;
                }
        }

	argsLeft = argc - optind;

	if (errFlag)
	{
		usage();
		exit(1);
	}

	/*
	** Work out what we here to do
	*/

	switch(argsLeft)
	{
		case 0:	dbShow++;
			break;
		case 1: relShow++;
			break;
		case 2:	fieldShow++;
			break;
		case 3:	if (strcmp(argv[optind+2],"_seq") == 0)
				seqShow++;
			else
				indexShow++;
			break;
		default:usage();
			exit(1);
	}


	/*
	**  Fire up mSQL
	*/

#ifdef WIN32
	wVersion = MAKEWORD(1,1);
	if (WSAStartup(wVersion, &wsaData) != 0)
	{
		printf("Can't initialise WinSOCK!\n\n");
		exit(0);
	}
#endif

	if (confFile)
	{
		msqlLoadConfigFile(confFile);
	}

	if ((sock = msqlConnect(host)) < 0)
	{
		printf("\nError connecting to database : %s\n\n", msqlErrMsg);
		exit(1);
	}

	if (!dbShow)
	{
		if(msqlSelectDB(sock,argv[optind]) < 0)
		{
			printf("\n%s\n\n",msqlErrMsg);
			msqlClose(sock);
			exit(1);
		}
	}


	/*
	** List the available databases if required
	*/

	if (dbShow)
	{
		res = msqlListDBs(sock);
		if (!res)
		{
			printf("\nERROR : Couldn't get database list!\n");
			exit(1);
		}
		printf("\n\n  +-----------------+\n");
		printf("  |    Databases    |\n");
		printf("  +-----------------+\n");
		while((cur = msqlFetchRow(res)))
		{
			printf("  | %-15.15s |\n", cur[0]);
		}
		printf("  +-----------------+\n\n");
		msqlFreeResult(res);
		msqlClose(sock);
		exit(0);

	}


	/*
	** List the available relations if required
	*/

	if (relShow)
	{

		res = msqlListTables(sock);
		if (!res)
		{
			printf("\n");
			printf("ERROR : Unable to list tables in database %s\n",
				argv[optind]);
			exit(1);
		}
		printf("\n\nDatabase = %s\n\n",argv[optind]);
		printf("  +---------------------+\n");
		printf("  |       Table         |\n");
		printf("  +---------------------+\n");
		while((cur = msqlFetchRow(res)))
		{
			printf("  | %-19.19s |\n", cur[0]);
		}
		printf("  +---------------------+\n\n");
		msqlFreeResult(res);
		msqlClose(sock);
		exit(0);
	}


	/*
	** List the attributes and types if required
	*/

	if (fieldShow)
	{
		/*
		** Get the list of attributes
		*/

		res = msqlListFields(sock,argv[optind+1]);
		if (!res)
		{
			printf("\nERROR : %s\n\n",msqlErrMsg);
			exit(1);
		}

		/*
		** Display the information
		*/

		printf("\nDatabase = %s\n",argv[optind]);
		printf("Table    = %s\n\n",argv[optind + 1]);
		printf(" +-----------------+----------+--------+----------+--------------+\n");
		printf(" |     Field       |   Type   | Length | Not Null | Unique Index |\n");
		printf(" +-----------------+----------+--------+----------+--------------+\n");
		while((curField = msqlFetchField(res)))
		{
			printf(" | %-15.15s | ",curField->name);
			switch(curField->type)
			{
				case INT_TYPE:
					strcpy(typeName,"int");
					break;

				case UINT_TYPE:
					strcpy(typeName,"uint");
					break;

				case DATE_TYPE:
					strcpy(typeName,"date");
					break;

				case TIME_TYPE:
					strcpy(typeName,"time");
					break;

				case MONEY_TYPE:
					strcpy(typeName,"money");
					break;

				case CHAR_TYPE:
					strcpy(typeName,"char");
					break;

				case TEXT_TYPE:
					strcpy(typeName,"text");
					break;

				case REAL_TYPE:
					strcpy(typeName,"real");
					break;

				case IDX_TYPE:
					strcpy(typeName,"index");
					break;
					
				default:
					strcpy(typeName,"Unknown");
					break;
			}
			printf("%-8.8s |",typeName);
			if (curField->type != IDX_TYPE)
			{
				printf(" %-6d |",curField->length);
				printf(" %-8.8s |",IS_NOT_NULL(curField->flags)?
					"Y":"N");
				printf(" N/A          |\n");
			}
			else
			{
				printf(" N/A    | N/A      |");
				printf(" %s |\n",IS_UNIQUE(curField->flags)?
					"Y           ": "N           ");
			}
		}
		printf(" +-----------------+----------+--------+----------+--------------+");
		printf("\n\n");
		msqlFreeResult(res);
		msqlClose(sock);
	}


	if (indexShow)
	{
		/*
		** Get the list of index fields
		*/

		res = msqlListIndex(sock,argv[optind+1],argv[optind+2]);
		if (!res)
		{
			printf("\nERROR : Couldn't find index '%s' in %s!\n\n",
				argv[optind+2], argv[optind+1]);
			exit(1);
		}

		/*
		** Display the information
		*/

		cur = msqlFetchRow(res);
		if (!cur)
		{
			printf("\nERROR : Couldn't find index '%s' in %s!\n\n",
				argv[optind+2], argv[optind+1]);
			exit(1);
		}
		if (strcmp(cur[0],"avl") == 0)
		{
			idxType = "Memory mapped AVL tree";
		}
		else
		{
			idxType = "Unknown index type";
		}
		printf("\nDatabase   = %s\n",argv[optind]);
		printf("Table      = %s\n",argv[optind + 1]);
		printf("Index      = %s\n",argv[optind + 2]);
		printf("Index Type = %s\n\n",idxType);

		printf("  +---------------------+\n");
		printf("  |       Field         |\n");
		printf("  +---------------------+\n");
		while((cur = msqlFetchRow(res)))
		{
			printf("  | %-19.19s |\n", cur[0]);
		}
		printf("  +---------------------+\n\n");
		msqlFreeResult(res);
		msqlClose(sock);
		exit(0);
	}

	if (seqShow)
	{
		m_seq	*seq;

		printf("\nDatabase       = %s\n",argv[optind]);
		printf("Table          = %s\n",argv[optind + 1]);
		seq = msqlGetSequenceInfo(sock, argv[optind + 1]);
		if (!seq)
		{
			printf("\nERROR : %s\n\n",msqlErrMsg);
			exit(1);
		}
		printf("Sequence Step  = %d\n",seq->step);
		printf("Sequence Value = %d\n",seq->value);
		msqlClose(sock);
		exit(0);
	}

	exit(0);
}
