All Downloads are FREE. Search and download functionalities are using the official Maven repository.

prerna.reactor.imports.NativeImporter Maven / Gradle / Ivy

The newest version!
package prerna.reactor.imports;

import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import prerna.algorithm.api.DataFrameTypeEnum;
import prerna.algorithm.api.ITableDataFrame;
import prerna.algorithm.api.SemossDataType;
import prerna.ds.OwlTemporalEngineMeta;
import prerna.ds.nativeframe.NativeFrame;
import prerna.ds.r.RDataTable;
import prerna.engine.api.IDatabaseEngine;
import prerna.engine.api.IHeadersDataRow;
import prerna.engine.api.IRDBMSEngine;
import prerna.engine.api.IRawSelectWrapper;
import prerna.masterdatabase.utility.MasterDatabaseUtility;
import prerna.masterdatabase.utility.MetadataUtility;
import prerna.query.querystruct.AbstractQueryStruct.QUERY_STRUCT_TYPE;
import prerna.query.querystruct.HardSelectQueryStruct;
import prerna.query.querystruct.SelectQueryStruct;
import prerna.query.querystruct.joins.BasicRelationship;
import prerna.query.querystruct.joins.IRelation;
import prerna.query.querystruct.selectors.IQuerySelector;
import prerna.query.querystruct.selectors.QueryColumnSelector;
import prerna.query.querystruct.selectors.QueryOpaqueSelector;
import prerna.query.querystruct.transform.QSAliasToPhysicalConverter;
import prerna.sablecc2.om.Join;
import prerna.sablecc2.om.PixelDataType;
import prerna.sablecc2.om.PixelOperationType;
import prerna.sablecc2.om.execptions.SemossPixelException;
import prerna.sablecc2.om.nounmeta.NounMetadata;
import prerna.util.Constants;
import prerna.util.Utility;

public class NativeImporter extends AbstractImporter {

	private static final Logger logger = LogManager.getLogger(NativeImporter.class);

	private static final String CLASS_NAME = NativeImporter.class.getName();
	
	private NativeFrame dataframe;
	private SelectQueryStruct qs;
	private Iterator it;

	public NativeImporter(NativeFrame dataframe, SelectQueryStruct qs) {
		this.dataframe = dataframe;
		this.qs = qs;
	}
	
	public NativeImporter(NativeFrame dataframe, SelectQueryStruct qs, Iterator it) {
		this.dataframe = dataframe;
		this.qs = qs;
		this.it = it;
	}
	
	@Override
	public void insertData() {
		// see if we can parse the query into a valid qs object
		SemossDataType[] executedDataTypes = null;
		String[] columnNames = null;
		IDatabaseEngine database = this.qs.retrieveQueryStructEngine();
		if(this.qs.getQsType() == QUERY_STRUCT_TYPE.RAW_ENGINE_QUERY && database instanceof IRDBMSEngine) {
			IRDBMSEngine rdbms = (IRDBMSEngine) database;
			// if you are RDBMS
			// we will make a new QS
			// and we will wrap you
			String query = ((HardSelectQueryStruct) this.qs).getQuery();//.trim();
//			if(query.endsWith(";")) {
//				query = query.substring(0, query.length()-1);
//			}
//			if(this.it == null) {
				// use a prepared statement
				// so we dont have to actually do the execution of the query
				PreparedStatement ps = null;
				ResultSetMetaData rsMeta = null;
				try {
					ps = rdbms.getPreparedStatement(query);
					rsMeta = ps.getMetaData();
					int numCols = rsMeta.getColumnCount();
					columnNames = new String[numCols];
					executedDataTypes = new SemossDataType[numCols];
					for(int i = 0; i < numCols; i++) {
						columnNames[i] = rsMeta.getColumnName(i+1);
						executedDataTypes[i] = SemossDataType.convertStringToDataType(rsMeta.getColumnTypeName(i+1));
					}
				} catch (SQLException e) {
					logger.error(Constants.STACKTRACE, e);
				} finally {
					if(ps != null) {
						try {
							ps.close();
						} catch (SQLException e) {
							logger.error(Constants.STACKTRACE, e);
						}
						if(rdbms.isConnectionPooling()) {
							try {
								ps.getConnection().close();
							} catch (SQLException e) {
								logger.error(Constants.STACKTRACE, e);
							}
						}
					}
				}
//				try {
//					StringBuilder newQueryB = new StringBuilder(" select * from (" + query + ") as customQuery ");
//					newQueryB = ((IRDBMSEngine) database).getQueryUtil().getFirstRow(newQueryB);
//					this.it = WrapperManager.getInstance().getRawWrapper(database, newQueryB.toString());
//				} catch (Exception e) {
//					logger.error(Constants.STACKTRACE, e);
//					// one more time
//					// try as well w/o changes - too bad on size...
//					try {
//						this.it = WrapperManager.getInstance().getRawWrapper(database, query);
//					} catch (Exception e1) {
//						logger.error(Constants.STACKTRACE, e1);
//						throw new SemossPixelException(
//								new NounMetadata("Error occurred executing query before loading into frame", 
//										PixelDataType.CONST_STRING, PixelOperationType.ERROR));
//					}
//				} finally {
//					if(this.it != null) {
//						((IRawSelectWrapper) this.it).cleanUp();
//					}
//				}
//			}
			
			String customFromAlias = "customquery";
			SelectQueryStruct newQs = new SelectQueryStruct();
			newQs.setEngineId(this.qs.getEngineId());
			newQs.setEngine(this.qs.getEngine());
			newQs.setCustomFrom(query);
			newQs.setCustomFromAliasName(customFromAlias);
			for(String p : columnNames) {
				QueryColumnSelector selector = new QueryColumnSelector();
				selector.setTable(customFromAlias);
				selector.setTableAlias(customFromAlias);
				selector.setColumn(p);
				String alias = p;
				while(alias.contains("__")) {
					alias = alias.replace("__", "_");
				}
				selector.setAlias(alias);
				newQs.addSelector(selector);
			}
			
			// swap the qs reference
			newQs.setBigDataEngine(this.qs.getBigDataEngine());
			newQs.setPragmap(this.qs.getPragmap());
			
			this.qs = newQs;
			this.qs.setQsType(QUERY_STRUCT_TYPE.ENGINE);
//			// lets see what happens
//			OpaqueSqlParser parser = new OpaqueSqlParser();
////			SqlParser parser = new SqlParser();
////			String query = ((HardSelectQueryStruct) this.qs).getQuery();
//			try {
//				SelectQueryStruct newQs = this.qs.getNewBaseQueryStruct();
//				newQs.merge(parser.processQuery(query));
//				// we were able to parse successfully
//				// override the reference
//				this.qs = newQs;
//				this.qs.setQsType(QUERY_STRUCT_TYPE.RAW_ENGINE_QUERY);
//				
//				// we need to figure out the columns if there is a *
//				cleanUpSelectors(this.qs.getEngineId(), this.qs.getSelectors(), this.qs.getRelations());
//			} catch (Exception e) {
//				// we were not successful in parsing :/
//				classLogger.error(Constants.STACKTRACE, e);
//			}
		} else {
			if(it != null && (it instanceof IRawSelectWrapper)) {
				executedDataTypes = ((IRawSelectWrapper) it).getTypes();
			}
		}
		boolean ignore = true;
		QUERY_STRUCT_TYPE qsType = this.qs.getQsType();
		if(qsType == QUERY_STRUCT_TYPE.ENGINE 
				|| qsType == QUERY_STRUCT_TYPE.RAW_ENGINE_QUERY
				|| qsType == QUERY_STRUCT_TYPE.RAW_JDBC_ENGINE_QUERY
				) {
			ignore = MetadataUtility.ignoreConceptData(this.qs.getEngineId());
		} else if (qsType == QUERY_STRUCT_TYPE.FRAME && qs.getFrame().getFrameType() == DataFrameTypeEnum.NATIVE) {
			ignore = MetadataUtility.ignoreConceptData(((NativeFrame)qs.getFrame()).getEngineId());
			this.qs.setEngineId( ((NativeFrame)qs.getFrame()).getEngineId() );
			this.qs.setQsType(QUERY_STRUCT_TYPE.ENGINE);
			this.qs = QSAliasToPhysicalConverter.getPhysicalQs(this.qs, qs.getFrame().getMetaData());			
		}

		ImportUtility.parseNativeQueryStructIntoMeta(this.dataframe, this.qs, ignore, executedDataTypes);
		this.dataframe.mergeQueryStruct(this.qs);
	}

	@Override
	public void insertData(OwlTemporalEngineMeta metaData) {
		this.dataframe.setMetaData(metaData);
		this.dataframe.mergeQueryStruct(this.qs);
	}

	@Override
	public ITableDataFrame mergeData(List joins) throws Exception {
		QUERY_STRUCT_TYPE qsType = this.qs.getQsType();
		String engineId = this.dataframe.getEngineId();
		
		if(qsType == QUERY_STRUCT_TYPE.ENGINE && engineId.equals(this.qs.getEngineId())) {
			boolean ignore = MetadataUtility.ignoreConceptData(engineId);
			if(ignore) {
				// this join may not be defined within the QS itself
				// as we join on all properties
				appendNecessaryRels(joins);
			}
			ImportUtility.parseNativeQueryStructIntoMeta(this.dataframe, this.qs, ignore, null);
			this.dataframe.mergeQueryStruct(this.qs);
			return this.dataframe;
		} else {
			// this is the case where we are going across databases or doing some algorithm
			// need to persist the data so we can do this
			// we will flush and return a new frame to accomplish this
			return generateNewFrame(joins);
		}
	}
	
	/**
	 * Need to add additional joins that are part of the merge
	 * Since we do not really have TABLE, join, TABLE anymore in RDBMS
	 * Yet I need to know what the join is
	 * @param joins
	 */
	public void appendNecessaryRels(List joins) {
		Set relations = this.qs.getRelations();
		List selectors = this.qs.getSelectors();
		
		int numJoins = joins.size();
		List relsToAdd = new ArrayList<>();
		
		J_LOOP : for(int i = 0; i < numJoins; i++) {
			Join j = joins.get(i);
			BasicRelationship jRel = new BasicRelationship(new String[] {j.getRColumn(), j.getJoinType(), j.getLColumn()});
			for(IRelation rel : relations) {
				if(jRel.equals(rel)) {
					continue J_LOOP;
				}
			}
			relsToAdd.add(jRel);
			// go through the selectors
			// if the qualifier is a selector
			// we want to remove it
			// since it is the join column
			Iterator it = selectors.iterator();
			while(it.hasNext()) {
				if(it.next().getQueryStructName().equals(j.getRColumn())) {
					it.remove();
					break;
				}
			}
		}
		
		for(IRelation rel : relsToAdd) {
			this.qs.addRelation(rel);
		}
	}
	
	/**
	 * Generate a new frame from the existing native query
	 * @param joins
	 * @return
	 * @throws Exception 
	 */
	private ITableDataFrame generateNewFrame(List joins) throws Exception {
		// first, load the entire native frame into rframe
		SelectQueryStruct nativeQs = this.dataframe.getQueryStruct();
		// need to convert the native QS to properly form the RDataTable
		nativeQs = QSAliasToPhysicalConverter.getPhysicalQs(nativeQs, this.dataframe.getMetaData());
		IRawSelectWrapper nativeFrameIt = this.dataframe.query(nativeQs);
		try {
			if(!FrameSizeRetrictions.sizeWithinLimit(nativeFrameIt.getNumRecords())) {
				SemossPixelException exception = new SemossPixelException(
						new NounMetadata("Frame size is too large, please limit the data size before proceeding", 
								PixelDataType.CONST_STRING, 
								PixelOperationType.FRAME_SIZE_LIMIT_EXCEEDED, PixelOperationType.ERROR));
				exception.setContinueThreadOfExecution(false);
				throw exception;
			}
		} catch (SemossPixelException e) {
			throw e;
		} catch (Exception e) {
			logger.error(Constants.STACKTRACE, e);
			throw new SemossPixelException(e.getMessage());
		}
		
		RDataTable rFrame = new RDataTable(this.in.getRJavaTranslator(LogManager.getLogger(CLASS_NAME)), Utility.getRandomString(8));
		RImporter rImporter = new RImporter(rFrame, nativeQs, nativeFrameIt);
		rImporter.insertData();
		
		// now, we want to merge this new data into it
		IRawSelectWrapper mergeFrameIt = null;
		try {
			mergeFrameIt = ImportUtility.generateIterator(this.qs, this.dataframe);
		} catch (Exception e) {
			logger.error(Constants.STACKTRACE, e);
			throw new SemossPixelException(
					new NounMetadata("Error occurred executing query before loading into frame", 
							PixelDataType.CONST_STRING, PixelOperationType.ERROR));
		}
		try {
			if(!FrameSizeRetrictions.importWithinLimit(rFrame, mergeFrameIt)) {
				SemossPixelException exception = new SemossPixelException(
						new NounMetadata("Frame size is too large, please limit the data size before proceeding", 
								PixelDataType.CONST_STRING, 
								PixelOperationType.FRAME_SIZE_LIMIT_EXCEEDED, PixelOperationType.ERROR));
				exception.setContinueThreadOfExecution(false);
				throw exception;
			}
		} catch (Exception e) {
			logger.error(Constants.STACKTRACE, e);
			throw new SemossPixelException(e.getMessage());
		}
		
		rImporter = new RImporter(rFrame, this.qs, mergeFrameIt);
		rImporter.mergeData(joins);
		return rFrame;
	}
	
	/**
	 * This method is here to clean up and properly add the columns when there is a * in the query
	 * @param engineId
	 * @param selectors
	 * @param rels
	 */
	private void cleanUpSelectors(String engineId, List selectors, Set rels) {
		String origTable = null;
		boolean queryAll = false;
		int foundIndex = -1;
		
		for(int i = 0; i < selectors.size(); i++) {
			IQuerySelector s = selectors.get(i);
			if(s instanceof QueryOpaqueSelector) {
				if(((QueryOpaqueSelector)s).getQuerySelectorSyntax().equals("*")) {
					foundIndex = i;
					origTable = ((QueryOpaqueSelector)s).getTable();
					queryAll = true;
					break;
				}
			}
		}
		
		if(queryAll) {
			// query all pulls from every table
			// including the joisn
			List tables = new Vector();
			tables.add(origTable.toLowerCase());
			
			for(String[] r : rels) {
				String from = r[0];
				if(from.contains("__")) {
					from = from.split("__")[0];
				}
				if(!tables.contains(from)) {
					tables.add(from.toLowerCase());
				}
				
				String to = r[2];
				if(to.contains("__")) {
					to = to.split("__")[0];
				}
				if(!tables.contains(to)) {
					tables.add(to.toLowerCase());
				}
			}

			boolean multiTable = tables.size() > 1;
			Collection possibleSelectors = MasterDatabaseUtility.getSelectorsWithinDatabaseRDBMS(engineId);
			for(String pSelector : possibleSelectors) {
				if(pSelector.contains("__")) {
					String possibleT = pSelector.split("__")[0];
					if(tables.contains(possibleT.toLowerCase())) {
						if(multiTable) {
							qs.addSelector(new QueryColumnSelector(pSelector, pSelector));
						} else {
							qs.addSelector(new QueryColumnSelector(pSelector));
						}
					}
				}
			}
			
			// now we need to remove the index that we had found
			qs.getSelectors().remove(foundIndex);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy