/*  ALTER TABLE tablename ADD fieldname 
 *  ALTER TABLE tablename DROP COLUMN fieldname
 */
#define USAGEMSG "usage: ALTER TABLE tablename ADD fieldname [nomaintain]\n ..or.. ALTER TABLE tablename DROP COLUMN fieldname [nomaintain]\n" 

#include "tdhkit.h"
#include "shsql.h"

extern int GL_make_unique_string();

#define ADD 0
#define DROP 1

int
main( argc, argv )
int argc;
char **argv;
{
int i, mode, ifld, stat;
char buf[512];
char tablename[MAXPATH], fieldname[128];
char fakename[MAXPATH];
char uniq[80], altname[80];
int skipmaint;


if( argc < 5 || argc > 7 ) {
	fprintf( stderr, "%s", USAGEMSG );
	exit( 1 );
	}

/* process config file.. */
stat = SHSQL_allconfig();
if( stat != 0 ) exit( 1 );


skipmaint = 0;

if( stricmp( argv[3], "add" )==0 ) {
	if( argc < 5 || argc > 6 ) {
		fprintf( stderr, "usage: ALTER TABLE tablename ADD fieldname\n" );
		exit( 1 );
		}
	mode = ADD;
	strcpy( fieldname, argv[4] );
	if( argc == 6 ) { 
		if( strnicmp( argv[5], "nomaint", 7 )==0 ) skipmaint = 1; 
		else	{
			fprintf( stderr, "usage: ALTER TABLE tablename ADD fieldname\n" );
			exit( 1 );
			}
		}
	}
else if ( stricmp( argv[3], "drop" )==0 && stricmp( argv[4], "column" )==0 ) {
	if( argc < 6 || argc > 7 ) {
		fprintf( stderr, "usage: ALTER TABLE tablename DROP COLUMN fieldname\n" );
		exit( 1 );
		}
	mode = DROP;
	strcpy( fieldname, argv[5] );
	if( argc == 7 ) { 
		if( strnicmp( argv[6], "nomaint", 7 )==0 ) skipmaint = 1; 
		}
	}
else	{
	fprintf( stderr, "%s", USAGEMSG );
	exit( 1 );
	}
	
strcpy( tablename, argv[2] );

if( GL_member( tablename[0], "/.$" )) { 
	fprintf( stderr, "alter: may be used with database table files only (%s)\n", tablename ); 
	exit( 1 ); 
	}

stat = SHSQL_loadfieldmap( tablename );
if( stat != 0 ) { 
	fprintf( stderr, "alter: invalid table name (%s)\n", tablename ); 
	exit( 1 ); 
	}


ifld = fieldmap( fieldname );
if( mode == DROP && ifld < 0 ) {
	fprintf( stderr, "alter: %s is not a valid field name for table '%s'\n", fieldname, tablename );
	exit( 1 );
	}
else if( mode == ADD && ifld >= 0 ) {
	fprintf( stderr, "alter: field %s already exists in table '%s'\n", fieldname, tablename );
	exit( 1 );
	}

stat = SHSQL_lock( tablename );
if( stat != 0 ) {
	fprintf( stderr, "alter: table %s is locked against writing.. cannot proceed\n", tablename );
	exit( 1 );
	}

sprintf( buf, "Note: starting ALTER TABLE %s %s %s", tablename, argv[3], fieldname );
SHSQL_err( 404, buf, "" );

GL_make_unique_string( uniq, 0 );
sprintf( altname, "__tmpmaint_%s", uniq );

/* keep a backup copy.. */
strcpy( fakename, tablename );
for( i = 0; fakename[i] != '\0'; i++ ) if( fakename[i] == '/' ) fakename[i] = '!';
sprintf( buf, "(cd %s/data; cp -p %s %s/alter.%s)", SHSQL_projdir, tablename, TDH_tmpdir, fakename );
system( buf );

if( mode == DROP ) {

	/* delete field, writing result into a tmp file */
	if( SHSQL_bin[0] == '\0' ) sprintf( buf, "cat %s/data/%s | shsql_fldsel -H -o %s -p > %s/data/%s", 
		SHSQL_projdir, tablename, fieldname, SHSQL_projdir, altname );
	else sprintf( buf, "cat %s/data/%s | %s/shsql_fldsel -H -o -p %s > %s/data/%s", 
		SHSQL_projdir, tablename, SHSQL_bin, fieldname, SHSQL_projdir, altname );
	/* fprintf( stderr, "alter is invoking: %s\n", buf ); */
	system( buf );
	}
else if( mode == ADD ) {

	/* add field, writing result into a tmp file */
	if( SHSQL_bin[0] == '\0' ) sprintf( buf, "cat %s/data/%s | shsql_fldsel -H -a %s \"%s\" -p > %s/data/%s", 
					SHSQL_projdir, tablename, fieldname, TDH_dbnull, SHSQL_projdir, altname );

	else sprintf( buf, "cat %s/data/%s | %s/shsql_fldsel -H -a %s \"%s\" -p > %s/data/%s", 
		SHSQL_projdir, tablename, SHSQL_bin, fieldname, TDH_dbnull, SHSQL_projdir, altname );

	/* fprintf( stderr, "alter is invoking: %s\n", buf ); */
	system( buf );
	}

if( !skipmaint ) {
	if( SHSQL_bin[0] == '\0' ) sprintf( buf, "tabmaint %s -n %s", tablename, altname );
	else sprintf( buf, "%s/tabmaint %s -n %s", SHSQL_bin, tablename, altname );
	system( buf );
	}

/* move temp file -> real file */
stat = SHSQL_readlock( tablename, 1 );
if( stat != 0 ) { SHSQL_unlock(); exit( 1 ); }

/* the following doesn't seem to be necessary in some cases.. depends on tabmaint -n behavior? */
sprintf( buf, "(cd %s/data; mv %s %s 2>/dev/null)", SHSQL_projdir, altname, tablename );  
system( buf );

SHSQL_readlock( tablename, 0 );
SHSQL_unlock();

if( skipmaint ) SHSQL_err( 405, "Note: ALTER TABLE finished, follow-up maintenance not elected", tablename );
else SHSQL_err( 405, "Note: ALTER TABLE finished", tablename );
exit( 0 );
}
