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

org.jclarion.clarion.util.FileState Maven / Gradle / Ivy

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