org.jclarion.clarion.util.FileState Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of clarion-runtime Show documentation
Show all versions of clarion-runtime Show documentation
JClarion runtime environment
The newest version!
/**
* Copyright 2010, by Andrew Barnham
*
* The contents of this file are subject to
* GNU Lesser General Public License (LGPL), v.3
* http://www.gnu.org/licenses/lgpl.txt
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
*/
package org.jclarion.clarion.util;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.IdentityHashMap;
import java.util.Map;
import org.jclarion.clarion.ClarionKey;
import org.jclarion.clarion.ClarionMemoryChangeListener;
import org.jclarion.clarion.ClarionObject;
import org.jclarion.clarion.jdbc.AbstractJDBCSource;
import org.jclarion.clarion.memory.CMem;
/**
* Model state of JDBC Connection. This same object is used
* for current state and saved states
*
* @author barney
*/
public class FileState
{
public static class Global
{
public int openCount;
public AbstractJDBCSource source;
public String name;
public String[] fieldNames;
public int[] types;
public boolean[] autoincrementing;
public boolean[] nonull;
}
public Global global;
/**
* Read mode/state of the connection
*
* NONE - no reading occurring
*
* RESET - file/key is positioned but no reading yet
* FORWARD - we are reading forward
* BACK - we are reading backwards
* RESTORED - we have been restored file that was previously
* - either in Forward or Back mode, but we have not
* yet fully restored iterator position
* (iterator restore is lazy)
*
* USER - user defined SQL was executed
*/
public enum Mode { None, Reset, Forward, Back, Restored, User };
public Mode mode;
public ClarionObject[] fields;
/**
* catalog of buffer columns that have been modified
*/
public boolean[] changed;
/**
* catalog of buffer columns that have been flagged as null
*/
public boolean[] isnull;
private static class ResultSetCount
{
int count;
}
/**
* Current Result Set/etc
*/
public PreparedStatement statement;
public ResultSet result;
public ResultSetCount resultSetCount;
/**
* Current scan key (if any)
*/
public ClarionKey scanKey;
public ClarionObject[] scanFields;
public ClarionObject quickScanBuffer;
/**
* Primary key and position
*/
public ClarionKey primaryKey;
public ClarionObject[] primaryKeyFields;
/**
* Current scan position
*/
public CMem position;
/**
* Ignore changes made to parameters as these are being done by
* internal ClarionFile object
*/
public boolean ignoreChange;
/**
* Run following SQL before PUT() if expression fails then
* fail PUT(). Post PUT clear expression
*/
public ClarionObject[] watchBuffer;
/**
* is watch armed. If true On next read - set watch expression
*/
public boolean watchArmed;
public ClarionMemoryChangeListener[] listeners;
public StringBuilder select;
/*=================================
* Optimisation/performance considerations
*=================================
*/
/**
* Limits - when scanning very large files say 10,000s of records in a browse, user
* usually only wants to see the first 20 or so. Isntead of pulling back 10,000s of
* records per scan across JDBC - limit number of records to pull back. If limit is
* exhausted, then invisibly reset the scan to get the next block of records
*/
public int limit=0; // only pull back # of records at a time on a scan.
public int currentLimit=0; // current limit in effect on curent scan in progress
public int readCount=0; // # of records read so far in a limited scan
public int offset=0; // when initiating a scan - specify given offset
/**
* Key binding. When using keys that are composite fields, it is very common that
* the program wants to 'fix' the first key and only scan second key. For example
* stock(franchise,partnum) - user may only want to look at parts in a given franchise
* But way clarion files work is that if I say all parts from franchise 2, partnum
* '1234' then all franchises above 2 are considered as well.
*
* When binding is in effect it works similar to limits. The initial query assumes that
* only franchise=2 is wanted. But if user executes 'next' statement beyond this
* then it will invisibly rewrite the query to handle this.
*
* This is beneficial in postgres at least because I had trouble getting postgres to
* optimise the following well
*
* franchise>2 OR (franchise=2 and partnum>='1234')
*
* Under some circumstances, instead of selecting a index scan starting at (2,'1234')
* sometimes postgrs would do a index scan at (2,) only - and filter records prior
* to 1234. For large data sets this can be very inefficient. But when I break it up into
* two queries i.e.
* a) franchise=2 and partnum>='1234'
* b) franchise>2
*
* The system optimises quite well
*/
public boolean keyBinding; // true allow key binding even if limit is still 0.
public boolean isBounded; // true if current scan is bounded.
public boolean disableBinding;
/**
* Quick scan has a comparable in original clarion. Browse tables force reset
* when scrolling through parts instead of continuing to read the already established
* statement.
*
* Clearly this is inefficient. Clarion worked around this with a quickscan setting.
* What that setting does in clarion is unclear, documentation talks about 'buffering'
* which I assume is caching etc.
*
* For this implementation - quickScan merely intercepts key methods. Specifically:
* reset() - if resetting a scan that is already occurring in scan position matches
* the currently cached position - enable quickScan to continue to 'use' the existing scan
*/
public boolean quickScan;
public boolean quickScanResetActivated; // if active - iterate() needs to skip and pretend it got a record
public FileState(FileState base)
{
this(base.global);
}
public FileState()
{
this(new Global());
}
public FileState(Global global)
{
this.mode=Mode.None;
this.position=CMem.create();
this.result=null;
this.scanKey=null;
this.scanFields=null;
this.quickScanBuffer=null;
this.changed=null;
this.isnull=null;
this.quickScan=false;
this.quickScanResetActivated=false;
this.primaryKey=null;
this.primaryKeyFields=null;
this.watchArmed=false;
this.watchBuffer=null;
this.global=global;
/*
this.source=null;
this.name=null;
this.fields=null;
this.fieldNames=null;
this.types=null;
this.listeners=null;
this.select=null;
*/
}
public void closeCursor()
{
closeCursor(true);
}
public void closeCursor(boolean clearKeyAndPosition)
{
closeCursor(clearKeyAndPosition,true);
}
public void closeCursor(boolean clearKeyAndPosition,boolean clearMode)
{
if (resultSetCount!=null) {
if (resultSetCount.count>0) {
resultSetCount.count--;
}
if (resultSetCount.count==0) {
resultSetCount=null;
}
}
if (result != null) {
if (resultSetCount == null) {
try {
result.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
result = null;
}
if (statement != null) {
if (resultSetCount == null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
statement = null;
}
this.resultSetCount = null;
if (clearMode) this.mode=Mode.None;
if (clearKeyAndPosition) {
this.position.reset();
this.scanKey=null;
this.isBounded=false;
if (this.primaryKeyFields!=null) {
for (int scan=0;scan fieldIndexMap;
public int getFieldIndex(ClarionObject o)
{
if (fieldIndexMap==null) {
fieldIndexMap=new IdentityHashMap();
for (int scan=0;scan
© 2015 - 2025 Weber Informatics LLC | Privacy Policy