import os from flask import Blueprint, render_template, render_template_string, redirect, request, session from flask_wtf import FlaskForm from wtforms.fields import DateTimeField, SubmitField, StringField, SelectMultipleField from datetime import datetime from recovery.lib.common.connecter import Connecter from recovery.lib.function.Outputter import Output from recovery.lib.function.Writer import csvwrite import pandas as pd class MyForm(FlaskForm): startdate = DateTimeField(id='startdate',format='%Y-%m-%d %H:%M:%S') enddate = DateTimeField(id='enddate', format='%Y-%m-%d %H:%M:%S') submit = SubmitField("Submit") class SchemaForm(FlaskForm): source = StringField("source") target = StringField("target") submit = SubmitField("Submit") class TableForm(FlaskForm): startdate = DateTimeField("Start Date", format='%Y-%m-%d %H:%M:%S') enddate = DateTimeField("End Date", format='%Y-%m-%d %H:%M:%S') source = StringField("source") target = StringField("target") tables = SelectMultipleField("tables") submit = SubmitField("Submit") class SubmitForm(FlaskForm): startdate = DateTimeField("Start Date", format='%Y-%m-%d %H:%M:%S') enddate = DateTimeField("End Date", format='%Y-%m-%d %H:%M:%S') source = StringField("source") target = StringField("target") tables = SelectMultipleField("tables") submit = SubmitField("Submit") recover = Blueprint('recover', __name__, template_folder='templates') @recover.route('/daterange', methods=["GET", "POST"]) def daterange(): session.clear() form = MyForm() if request.method == "POST": tempdate = datetime.strptime(request.form['startdate'], '%m/%d/%Y %I:%M %p') timestamp = datetime.timestamp(tempdate) startdate = datetime.fromtimestamp(timestamp)#.strftime('%Y-%m-%d %H:%M:%S') session["startdate"] = startdate tempdate = datetime.strptime(request.form['enddate'], '%m/%d/%Y %I:%M %p') timestamp = datetime.timestamp(tempdate) print(timestamp) enddate = datetime.fromtimestamp(timestamp)#.strftime('%Y-%m-%d %H:%M:%S') print(enddate) session["enddate"] = enddate return redirect("schemas") return render_template('recover/daterange.html', form=form) @recover.route('/schemas', methods=["GET", "POST"]) def schemas(): form = SchemaForm() connector = Connecter() getschemas = "SELECT dbname,schemaname,dbuser,dbpassword,sfaccount,sfwarehouse FROM public.targets" (pgconn,pgcur) = connector.open_pgsql('public') pgcur.execute(getschemas) schemarows = pgcur.fetchall() if request.method == "POST": sourcefield = request.form['source'].split(',') session["source"] = sourcefield[0] session["sourceuser"] = sourcefield[1] session["sourcepassword"] = sourcefield[2] session["sourceaccount"] = sourcefield[3] session["sourcewarehouse"] = sourcefield[4] targetfield = request.form['target'].split(',') session["target"] = targetfield[0] session["targetuser"] = targetfield[1] session["targetpassword"] = targetfield[2] session["targetaccount"] = targetfield[3] session["targetwarehouse"] = targetfield[4] return redirect("tables") return render_template('recover/schemas.html', form=form, schemarows=schemarows) @recover.route('/tables', methods=["GET", "POST"]) def tables(): form = TableForm() connector = Connecter() dbfield = session["source"].split('.') session['sourcedb'] = dbfield[0] session['sourceschema'] = dbfield[1] gettables = f"select distinct(table_name) from information_schema.columns where table_schema = '{dbfield[1]}' order by table_name;" session["sffrominfo"] = [ session["sourceaccount"], session["sourceuser"], session["sourcepassword"], session["sourcewarehouse"], session['sourcedb'], session['sourceschema'], ] (database, schema, conn) = connector.connect(session["sffrominfo"]) cur = conn.cursor() cur.execute(gettables) cur.get_results_from_sfqid(cur.sfqid) results = cur.fetchall() tablecount = len(results) if request.method == "POST": session['tablelist'] = request.form.getlist('tables') return redirect("verify") return render_template('recover/tables.html', form=form, results=results, tablecount=tablecount) @recover.route('/verify') def verify(): form = SubmitForm() if request.method == "POST": return redirect('sfexec') return render_template('recover/submit.html', form=form) @recover.route('/sfexec') def sfexec(): failed_tables = [] discrepancylist = [] mismatchlist = [] minuscountlist = [] outputter = Output() writer = csvwrite() fromdata = './recovery/data/from_data.csv' #fromdata = fromdatafile.valuename todata = './recovery/data/to_data.csv' #todata = todatafile.valuename recovereddata = './recovery/data/recovered_data.csv' #recovereddata = recovereddatafile.valuename table_ddl = [] table_ddls = {} connecter = Connecter() dbfield = session["source"].split('.') session["sffrominfo"] = [ session["sourceaccount"], session["sourceuser"], session["sourcepassword"], session["sourcewarehouse"], session['sourcedb'], session['sourceschema'], ] (fromdatabase, fromschema, fromconn) = connecter.connect(session["sffrominfo"]) fromcur = fromconn.cursor() (pgconn, pgcur) = connecter.open_pgsql(session['sourceschema']) dbfield = session["target"].split('.') session['targetdb'] = dbfield[0] session['targetschema'] = session['sourceschema'] session["sftoinfo"] = [ session["targetaccount"], session["targetuser"], session["targetpassword"], session["targetwarehouse"], session['targetdb'], session['targetschema'], ] (todatabase, toschema, toconn) = connecter.connect(session["sftoinfo"]) tocur = toconn.cursor() for tablename in session["tablelist"]: table_ddl.append( [ tablename, fromdatabase + "_" + tablename, todatabase + "_" + tablename, ] ) for tablename in session['tablelist']: get_ddl = f"SELECT get_ddl('TABLE','{tablename}');" fromcur.execute(get_ddl) fromcur.get_results_from_sfqid(fromcur.sfqid) results = fromcur.fetchall() ( fromtable, totable, minustable, recovertable, ) = writer.create_tables( pgconn, pgcur, fromconn, toconn, session['sourceschema'], tablename, results[0][0], session ) session['fromtable'] = fromtable session['totable'] = totable session['minustable'] = minustable session['recovertable'] = recovertable columnfield = session['fromtable'].split('.') tvar = session['exclude_list'].replace(',', "','") excluded_columns = f"'{tvar}'" get_columns = f"SELECT column_name FROM information_schema.columns WHERE table_schema = '{session['targetschema']}' AND table_name = '{columnfield[1].lower()}';" get_datacolumns = f"SELECT column_name FROM information_schema.columns WHERE table_schema = '{session['targetschema']}' AND table_name = '{columnfield[1].lower()}' AND column_name NOT IN ({excluded_columns});" pgcur.execute(get_columns) columnlist = [] columnlistquery = pgcur.fetchall() for row in columnlistquery: columnlist.append(row[0]) session['all_columns'] = ",".join(columnlist) pgcur.execute(get_datacolumns) columnlist = [] columnlistquery = pgcur.fetchall() for row in columnlistquery: columnlist.append(row[0]) session['data_columns'] = ",".join(columnlist) session['get_data'] = f" SELECT * FROM {tablename} WHERE ODS_EFF_ROW_DTM >= '{session['startdate']}' AND ODS_EFF_ROW_DTM <= '{session['enddate']}';" fromcur.execute(session['get_data']) fromcur.get_results_from_sfqid(fromcur.sfqid) fromresults = fromcur.fetchall() session['from_rows'] = len(fromresults) if session['from_rows'] > 0: valuelist = [] for column in fromresults[0]: valuelist.append('%s') valueslist = ','.join(valuelist) fromargs = ','.join(pgcur.mogrify(f"({valueslist})", i).decode('utf-8') for i in fromresults) pgcur.execute(f"INSERT INTO {fromtable} ({session['all_columns']}) VALUES {fromargs}") else: print("0 Rows received.") pgconn.commit() tocur.execute(session['get_data']) tocur.get_results_from_sfqid(tocur.sfqid) toresults = tocur.fetchall() session['to_rows'] = len(toresults) toargs = ','.join(pgcur.mogrify(f"({valueslist})", i).decode('utf-8') for i in toresults) if len(toresults) > 0: pgcur.execute(f"INSERT INTO {totable} ({session['all_columns']}) VALUES {toargs}") else: print("0 Rows received.") pgconn.commit() session['minusquery'] = f"SELECT {session['data_columns']} FROM {fromtable} EXCEPT SELECT {session['data_columns']} FROM {totable};" pgcur.execute(session['minusquery']) minusresults = pgcur.fetchall() session['minus_rows'] = len(minusresults) if session['minus_rows'] > 0: valuelist = [] for column in minusresults[0]: valuelist.append('%s') valueslist = ','.join(valuelist) minusargs = ','.join(pgcur.mogrify(f"({valueslist})", i).decode('utf-8') for i in minusresults) pgcur.execute(f"INSERT INTO {minustable} ({session['data_columns']}) VALUES {minusargs}") pgconn.commit() valuelist = [] for column in fromresults[0]: valuelist.append('%s') valueslist = ','.join(valuelist) whereclausecolumns = session['data_columns'].split(',') whereclauselist = [] for column_name in whereclausecolumns: pgcur.execute(f"SELECT COUNT(*) FROM {minustable} WHERE {column_name} IS NULL;") result = pgcur.fetchone() if result[0] == 0: whereclauselist.append(f"A.{column_name} = B.{column_name}") recoverclause = " AND ".join(whereclauselist) datacolumns = session['all_columns'].split(',') selectcolumns = f"A.{',A.'.join(datacolumns)}" recoveryquery = f"INSERT INTO {recovertable} ({session['all_columns']}) SELECT {selectcolumns} FROM {fromtable} A, {minustable} B WHERE {recoverclause};" print(recoveryquery) pgcur.execute(recoveryquery) pgconn.commit() #pgcur.execute(f'SELECT * from {recovertable}') #recoverresults = pgcur.fetchall() #session['recovered_rows'] = len(recoverresults) #if session['recovered_rows'] > 0: # resultdf = pd.DataFrame() meta_columns = ['change_seq','change_oper','change_mask','stream_position','operation','transaction_id','timestamp'] selectstatement = f'SELECT * from {recovertable}' recover_query = pd.read_sql_query(selectstatement, pgconn) resultdf = pd.DataFrame(recover_query) resultdf.to_csv('results.csv', index=False) recoveredcsv = open(f'{tablename}.csv', 'w') resultcsv = open('results.csv', 'r') for index, row in enumerate(resultcsv): line = row.replace('UNKNOWN', '') linefield = line.split(',') for idx, fieldname in enumerate(linefield): if "memory at" in fieldname: linefield[idx] = '' if index == 0: for index1, lfield in enumerate(linefield): if lfield in meta_columns: newfield = f'"{lfield}"' linefield[index1] = newfield line = ",".join(linefield) elif index > 0: linefield[2] = '' line = ",".join(linefield) recoveredcsv.write(f'{line}') resultcsv.close() recoveredcsv.close() os.unlink('results.csv') try: print("Transferring file.......") tocur.execute(f"PUT file://{tablename}.csv @%{tablename} AUTO_COMPRESS=TRUE OVERWRITE=TRUE;") except Exception as e: print(e) else: print('Copying data.......') tocur.execute(f"copy into {tablename} file_format = (type = csv field_delimiter = ',' skip_header = 1 error_on_column_count_mismatch=false) ENFORCE_LENGTH = FALSE;"); else: print('0 rows to process.') pgconn.commit() return render_template('recover/sfexec.html')