Showing posts with label Utilities. Show all posts
Showing posts with label Utilities. Show all posts

26 March 2011

Object Pooling


While writing eXtremecode's business layer, I found some performance related issues when creating a large number of business objects.
Each business object contains some heavy objects which require comparatively larger amount of system memory. Firstly I was creating these objects on each creation of business object, later I realized that these objects should be shared by related business objects, but that was not the solution as business objects were being created in different threads. Finally I decided to make a pool of similar objects so each thread could request pooled objects and could use them independently.

Pooling Source Code

/** 
Copyright (c) 2010, Sheikh Abdul Wahid Ahmed
Details @ http://extremecodeworld.codeplex.com/license
**/

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Threading;


namespace EXtremecode.Common
{
    public interface IPooledObject
    {
        ObjectPool Pool
        {
            get;
            set;
        }
    }
 
 public class ObjectPool
    {
        private Stack<IPooledObject> pool = new Stack<IPooledObject>();
        private int poolSize;
        private int numberOfPooledObjectsCreated = 0;
        private int timeOut = 15000; // in millisecond
        private Func<IPooledObject> CreateObject;
        private AutoResetEvent autoReset = new AutoResetEvent(false);
        private string poolName = string.Empty;

        public ObjectPool(Func<IPooledObject> CreateObject)
            : this("UnKnown", CreateObject, 10, 15000)
        {}

        public ObjectPool(string poolName, Func<IPooledObject> CreateObject)
            : this(poolName, CreateObject, 10, 15000)
        { }

        public ObjectPool(Func<IPooledObject> CreateObject
                , int timeOut)
            : this("UnKnown", CreateObject, 10 ,timeOut)
        { }

        public ObjectPool(string poolName, Func<IPooledObject> CreateObject
                , int timeOut)
            : this(poolName, CreateObject, 10, timeOut)
        { }

        public ObjectPool(string poolName,Func<IPooledObject> CreateObject
            , int poolSize, int timeOut)
        {
            this.CreateObject = CreateObject;
            this.poolSize = poolSize;
            this.poolName = poolName;
            this.timeOut = timeOut;
        }

        public IPooledObject GetObject()
        {
            while (true)
            {
                lock (pool)
                {
                    if (pool.Count > 0)
                    {
                        //get object from the pool.
                        Console.WriteLine("[{0}] PooledObject Poped  (Opened Objects [{1}])"
                            , poolName
                            ,numberOfPooledObjectsCreated - pool.Count);
                        
                        return pool.Pop();
                        

                    }
                    else
                    {
                        if (numberOfPooledObjectsCreated < poolSize)
                        {
                            //numbers of pooled object has not crossed the limit yet
                            //so create new object and return
                            IPooledObject pooledObject = CreateObject();
                            if (pooledObject != null)
                            {
                                numberOfPooledObjectsCreated++;
                                pooledObject.Pool = this; //add self reference
                                //which will be used to get the object back into pool again. 
                            }
                            Console.WriteLine("[{0}] PooledObject Created  (Opened Objects [{1}])"
                                , poolName
                                , numberOfPooledObjectsCreated - pool.Count);

                            return pooledObject;
                            
                            
                        }
                    }



                    Console.WriteLine("[{0}] Waiting for PooledObject", poolName);
                    bool timeOutOccured = !autoReset.WaitOne(timeOut); 

                    if (timeOutOccured)
                    {
                        throw new Exception(
                            string.Format("object request from the pool '{0}' has been timeout"
                            , poolName));
                    }
                }
               
                
            }
            
            
        }

        [System.Runtime.CompilerServices.MethodImpl
        (System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
        public void ReleaseObject(IPooledObject pooledObject)
        {
            pool.Push(pooledObject);
            autoReset.Set();
            Console.WriteLine("[{0}] PooledObject Pushed  (Opened Objects [{1}])"
                , poolName
                , numberOfPooledObjectsCreated - pool.Count);
        }
        
    }

    
}

read more...

24 March 2011

Request or Task Scheduling


I worked on the product which was developed for reconciling bank transaction. That reconciliation was performed on the bases of priority. In order to execute priority based requests from different threads, I have written an scheduler for executing them. Following is the source code of that scheduler.

Source Code.

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Threading;

namespace EXtremecode.Common
{
    //each request must implement this interface. 
    public interface IScheduledProcess
    {
        void Execute();
        
    }
 
 public class PriorityComparer : IComparer<int>
    {
        #region IComparer<int> Members

        public int Compare(int x, int y)
        {
            return x - y;
        }

        #endregion
    }

    public enum PriorityLevel
    {
         High = 10
       , Normal = 5
       , Low = 1

    }
    public class ProcessSchedular
    {
        //for identifying a schedular
        private static Dictionary<string, ProcessSchedular>
            schedularDict = new Dictionary<string, ProcessSchedular>();

        //for priority based execution
        private SortedDictionary<int, Queue<IScheduledProcess>>
            queuesDict = new SortedDictionary<int, Queue<IScheduledProcess>>(
                new PriorityComparer());


        //for controlling termination of main thread.
        private volatile bool isRunning = false;

        //for letting single thread to be executed at a time.
        private AutoResetEvent autoReset = new AutoResetEvent(false);


        //it is used for time based schdular (without priority). All registed process will be executed simultaneously
        public event Action OnExecuteProcess;
        
        
        public static ProcessSchedular CreateInstance(string key)
        {
            ProcessSchedular processSchedular;
            if (schedularDict.ContainsKey(key))
            {
                processSchedular = schedularDict[key];
            }
            else
            {
                processSchedular = new ProcessSchedular();
                schedularDict.Add(key, processSchedular);
            }
            return processSchedular;

        }

        public static ProcessSchedular GetInstance(string key)
        {
            ProcessSchedular processSchedular = null;
            if (schedularDict.ContainsKey(key))
            {
                processSchedular = schedularDict[key];
            }

            return processSchedular;

        }

        
        //Add process to prioriy based schedular with normal priority
        public void AddProcess(IScheduledProcess process)
        {
            AddProcess(process, PriorityLevel.Normal);
        }

        //Add process to prioriy based schedular with provided priority
        public void AddProcess(IScheduledProcess process, PriorityLevel priorityLevel)
        {
            AddProcess(process, (int)priorityLevel);
        }


        [System.Runtime.CompilerServices.MethodImpl
        (System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
        public void AddProcess(IScheduledProcess process, int priorityLevel)
        {
            GetQueue(priorityLevel).Enqueue(process);
            autoReset.Set(); //every time single thread will me released.
        }


        public void StopScheduling()
        {
            isRunning = false;
        }
        
        public void StartTimeBasedScheduling(object objInterval)
        {
            int interval = (int)objInterval;
            isRunning = true;
            while (isRunning)
            {

                try
                {

                    if (OnExecuteProcess != null)
                    {
                        OnExecuteProcess();
                    }
                    Thread.Sleep(interval);
                }
                catch
                {
                    throw;
                }

            }
          
        }

        public void StartPriorityBasedScheduling()
        {
            isRunning = true;
            while (isRunning)
            {
                while (true)
                {
                    Queue<IScheduledProcess> queue
                        = GetQueueToExecute();

                    if (queue == null)
                    {
                        break;
                        //wait for next processes
                    }
                    else
                    {
                        try
                        {
                            queue.Dequeue().Execute();

                        }
                        catch
                        {
                            //thread should not be terminated
                            //process should handle this exception.
                        }
                    }
                }

                autoReset.WaitOne(15000,false);
            }
        }

        private Queue<IScheduledProcess> GetQueue(int priorityLevel)
        {

            Queue<IScheduledProcess> queue;
            if (queuesDict.ContainsKey(priorityLevel))
            {
                queue = queuesDict[priorityLevel];
            }
            else
            {
                queue = new Queue<IScheduledProcess>();
                queuesDict.Add(priorityLevel, queue);
            }

            return queue;
        }

        private Queue<IScheduledProcess> GetQueueToExecute()
        {
            foreach (int key in queuesDict.Keys)
            {
                if (queuesDict[key].Count > 0)
                {
                    return queuesDict[key];
                }
            }
            return null;
        }
    }
}

read more...

21 March 2011

Parsing a query or statement for Identifying Functions


Overview

I am working in the application which was previously integrated with Microsoft Great Plain system (Back-end SQL Server Database). Now it's going to be integrated with Oracle Financial (Back-end Oracle Database). When i analyzed application's current code, i found number of inline queries everywhere in the code. It would be very difficult to scan whole code and modify all queries for making them Oracle compliance. So rather to do this manual work, i decided to write a routine which would return an object after parsing the query. Once i would get the object, i could make required modification easily before sending it to the sever for execution.

Details

If you want to convert SQL Server's query to Oracle's, beside other modifications, you must need to replace all SQL Server's functions and their parameters with some Oracle compliance functions and parameters. This replacement depends on the name of SQL Server's functions as well as values and positions of their arguments/parameters.
Suppose we have the function from SQL Server query Convert(datetime,'23/02/2010',103). In order to make it Oracle compliance, it should be modified something like To_Date('23/02/2010','DD/MM/yyyy').
First argument of Convert function in above example is datetime which tells that function name should be replaced with To_Date. Third argument of Convert function is 103 which tell that To_Date function's second argument should be 'DD/MM/yyyy'.

IdentifyFunctions (parsing a query or statement)

This method parse the query and return a FunctionParameter object.
/// <summary>
        /// Identifying functions into a parameter.
        /// Whole statement or query is considered as a parameter.
        /// </summary>
        /// <param name="sb">A parameter or a statement. A parameter in case of recursive calling</param>
        /// <param name="startIndex"></param>
        /// <param name="endIndex"></param>
        /// <param name="flatListOfFunction">A flat list of all functions in a statement</param>
        /// <param name="parentFunction"> Function, the parameter belongs to. Null value in case of statement.</param>
        /// <returns></returns>
        public static FunctionParameter IdentifyFunctions(StringBuilder sb, int startIndex, int endIndex
            , SortedList<int, Function> flatListOfFunction
            , Function parentFunction)
        {

            //Parsing will be started for "index" position
            int index = startIndex;

            //This flag will be true where parsing will not be required. e.g "sample text" or 'sample text'
            bool blindMove = false;

            //Initialize flatListOfFunction
            if (flatListOfFunction == null)
            {
                flatListOfFunction = new SortedList<int, Function>();
            }



            //Passed value is considered a parameter. Each param may contain number of functions.
            FunctionParameter parameter
                = new FunctionParameter(sb, startIndex, endIndex, parentFunction);


            //Explicit return condition
            if (parameter.Statement == string.Empty)
            {
                return parameter;
            }

            //Fuction can be constructed with any of them enclosing chars. [{(
            //e.g. Function(),Function[] or Function{}
            Stack<char> enclosingChars = new Stack<char>();
            Stack<int> enclosingCharIndexs = new Stack<int>();

            //Variables for current function
            int currentFuncNameStartIndex = -1;
            int currentFuncNameEndIndex = -1;
            bool currentFuncNameEnded = false;
            char currentFuncEnclosingChar = '\0';
            Function currentFunction = null;


            //current text enclosing char
            char currentTextEnclosing = '\'';

            while (index <= endIndex)
            {
                char chr = sb[index];


                if (blindMove && chr != currentTextEnclosing)
                {
                    //Ignore current char, becuase blind move is true.
                    index++;
                    continue;
                }

                char? chrNext = (index + 1 < sb.Length)
                    ? sb[index + 1]
                    : (char?)null;

                char? chrPrev = (index > 0)
                    ? sb[index - 1]
                    : (char?)null;


                char? topEnclosingChar = (enclosingChars.Count > 0)
                        ? enclosingChars.Peek()
                        : (char?)null;

                int? topEnclosingCharIndex = (enclosingCharIndexs.Count > 0)
                       ? enclosingCharIndexs.Peek()
                       : (int?)null;

                switch (chr)
                {
                    // ' 
                    case '\'':
                    case '"':
                        if (topEnclosingChar == chr)
                        {
                            if (chrNext == chr)
                            {
                                //It is not enclosing (closing) char so skip these two chars
                                index += 2;
                                continue;
                            }
                            else if (chrPrev == '\\')
                            {
                                //Previous char was escaping char. so it is not closing of the text.
                            }

                            else
                            {
                                //It is enclosing (closing) char so pop the char from stacks.
                                enclosingChars.Pop();
                                enclosingCharIndexs.Pop();

                                //Parsing will be required for upcomming data.
                                blindMove = false;

                            }
                        }
                        else
                        {
                            //It is enclosing (opening) char so push it to the stacks.
                            enclosingChars.Push(chr);
                            enclosingCharIndexs.Push(index);

                            //Ignore parising of upcomming data untill we get closing char.
                            blindMove = true;

                        }
                        break;

                    // {([
                    case '{':
                    case '[':
                    case '(':

                        //This char may be for nested function 
                        //"Bracket found in the stack" means that it is opening for nested function.
                        // Nested functions will be handled by related iteration (Recursive Calling)
                        bool isNestedFunctionOpening = (enclosingChars.Count > 0);


                        //If it is not for nested functin then set function name's ending index.
                        if (!isNestedFunctionOpening)
                        {

                            //Set endIndex to previous of this index.
                            currentFuncNameEndIndex = index - 1;

                            //Enclosing char, (Can be used later at the time of statement manipulation).
                            currentFuncEnclosingChar = chr;

                            //Make function
                            currentFunction = new Function(sb
                                , currentFuncNameStartIndex
                                , currentFuncNameEndIndex
                                , currentFuncEnclosingChar
                                , parameter);

                            //Add function to main param
                            parameter.Functions.Add(currentFunction);


                            //Add into flat list
                            flatListOfFunction.Add(currentFuncNameEndIndex, currentFunction);



                        }
                        enclosingChars.Push(chr);
                        enclosingCharIndexs.Push(index);
                        break;

                    // )}]
                    case '}':
                    case ']':
                    case ')':

                        if (enclosingChars.Count == 0)
                        {
                            //There is no openning bracket for this char
                            throw new Exception(string.Format("opening char is missing index={0}    char={1}"
                                , index
                                , chr));
                        }

                        //This char may be for nested function 
                        //"More than one char found in the stack" means, it is closing for nested function.
                        bool isNestedFunctionClosing = (enclosingChars.Count > 1);

                        if (!isNestedFunctionClosing)
                        {
                            //It is closing of current function. 
                            //And previous index is the ending of its last parameter if any.

                            //Get its last param by recursive calling
                            FunctionParameter param = IdentifyFunctions(sb
                                , enclosingCharIndexs.Peek() + 1
                                , index - 1
                                , flatListOfFunction
                                , currentFunction);

                            //Add Param to function params List
                            if (currentFunction != null)
                            {
                                currentFunction.Parameters.Add(param);
                            }

                            //Pop function's opening char.
                            enclosingCharIndexs.Pop();
                            enclosingChars.Pop();


                            //Reset current function variables
                            currentFunction = null;
                            currentFuncNameStartIndex = -1;
                            currentFuncNameEndIndex = -1;

                        }
                        else
                        {
                            //Pop nested fuction opening char
                            enclosingCharIndexs.Pop();
                            enclosingChars.Pop();

                        }
                        break;

                    // ,
                    case ',':

                        //This char may be for nested function 
                        //"More than one char found in the stack" means, it is for nested function.
                        bool isNestedFunctionComma = (enclosingChars.Count > 1);


                        if (!isNestedFunctionComma

                            //commas outside the functions will be ignored. 
                            //If we find stack empty, it means this comma doesnt belog to any function.
                            && enclosingChars.Count > 0)
                        {
                            //Previous index is the ending of the last parameter of current function if any

                            //Get the param by recursive calling
                            FunctionParameter param = IdentifyFunctions(sb
                                , enclosingCharIndexs.Peek() + 1
                                , index - 1
                                , flatListOfFunction
                                , currentFunction);


                            //Add param to list
                            if (currentFunction != null)
                            {
                                currentFunction.Parameters.Add(param);
                            }

                            //Pop function's opening char (it may be a comma).
                            //Because after deciding first param boundary, function's opening char will get poped out the stacks.
                            enclosingCharIndexs.Pop();
                            enclosingChars.Pop();

                            //Push this char, it will be used for identifying starting of next param
                            enclosingCharIndexs.Push(index);
                            enclosingChars.Push(chr);
                        }
                        break;

                    // space or new line
                    case '\t':
                    case '\n':
                    case '\r':
                    case ' ':

                        //As a space has come, system is assuming it is either end of the function name
                        //or not part of the function name.
                        currentFuncNameEnded = true;
                        break;

                    default:
                        if ((chr >= '0' && chr <= '9')
                             || (chr >= 'a' && chr <= 'z')
                             || (chr >= 'A' && chr <= 'Z')
                             || (chr == '_')
                            ) //Possible chars for function name
                        {
                            bool isNestedFunctionText = (enclosingChars.Count > 0);

                            //if Char is from nested functions. system will assume that 
                            //function name has already been identified.
                            if (!isNestedFunctionText)
                            {
                                if (currentFuncNameEnded)
                                {
                                    //As current function name has already been ended.
                                    //and now we have another alpha numeric character.
                                    //it means last identified function name is not correct
                                    //So mark this char as start of the fuction name
                                    currentFuncNameStartIndex = index;
                                    currentFuncNameEnded = false;
                                }
                                else if (currentFuncNameStartIndex < 0)
                                {
                                    //it has no been intialized yet
                                    currentFuncNameStartIndex = index;
                                }
                            }
                        }
                        break;
                }
                index++;

            }

            return parameter;

        }

FunctionParameter object

FunctionParameter object is either a whole query/statement or an argument of a function. FunctionParameter object has a collection of Function objects FunctionParameter object belongs to a parent Function. (In case of whole statemet/query, parent Function object is null)
public class FunctionParameter
    {

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="startIndex"></param>
        /// <param name="endIndex"></param>
        /// <param name="parentFunction">Function, which this param belongs to</param>
        public FunctionParameter(StringBuilder source, int startIndex, int endIndex, Function parentFunction)
        {
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.source = source;
            this.functions = new List<Function>();
            this.parentFunction = parentFunction;
        }

        private int startIndex;
        public int StartIndex
        {
            get { return startIndex; }

            set
            {
                startIndex = value;

                //Statement shoud be re assigned.
                statement = null;
            }
        }

        private int endIndex;
        public int EndIndex
        {
            get { return endIndex; }
            set
            {
                endIndex = value;

                //Statement shoud be re assigned.
                statement = null;
            }
        }

        private StringBuilder source;
        public StringBuilder Source
        {
            get { return source; }
            set { source = value; }
        }

        private List<Function> functions;
        public List<Function> Functions
        {
            get { return functions; }
        }


        private Function parentFunction;
        public Function ParentFunction
        {
            get { return parentFunction; }
        }

        private string statement = null;
        public string Statement
        {
            get
            {
                if (statement == null)
                {
                    if (startIndex > endIndex
                        || startIndex < 0
                        || endIndex < 0)
                    {
                        //Parameter with empty text (empty statement)
                        statement = string.Empty;
                    }
                    else
                    {
                        statement = source.ToString(startIndex
                            , endIndex - startIndex + 1).Trim();
                    }
                }
                return statement;
            }
            set
            {
                int statementCurrentLength = 0;
                if (startIndex < 0)
                {
                    //Already empty text so no need to remove old text
                    startIndex = 0;
                }
                else if (endIndex > 0)
                {
                    //Remove old text
                    source.Remove(startIndex
                        , endIndex - startIndex + 1);

                    statementCurrentLength = endIndex - startIndex + 1;
                }

                //Insert new text
                source.Insert(startIndex, value);

                //Update endindex
                endIndex = startIndex + value.Length - 1;

                //Reassign statement.
                statement = value.Trim();

                //Offset: subtrace statementCurrentLength from value's length
                int offset = value.Length - statementCurrentLength;


                //Adjust onward functions and params indexes
                if (parentFunction != null)
                {
                    parentFunction.AdjustIndexes(offset, this);
                }



            }
        }

        public void AdjustIndexes(int offset)
        {
            AdjustIndexes(offset, null);
        }


        public void AdjustIndexes(int offset, Function requestingFunction)
        {

            if (requestingFunction == null)
            {
                endIndex = endIndex + offset;
                startIndex = startIndex + offset;
            }
            else
            {
                //It is requested from its own fuction so only endIndex adjustment is required.
                endIndex = endIndex + offset;
            }

            //Adjustment should be applied only for those statement's functions which come after requesting function.
            int index = (requestingFunction != null)
                ? functions.IndexOf(requestingFunction) + 1
                : 0;

            for (; index < functions.Count; index++)
            {
                functions[index].AdjustIndexes(offset);
            }

            //Notify parent function
            if (parentFunction != null
                && requestingFunction != null)
            {
                //If request from its own function, only then notification is required.
                parentFunction.AdjustIndexes(offset, this);
            }
        }


        public override string ToString()
        {
            return Statement;
        }
    }

Function object

Function object has a collection of FunctionParameter objects. Function object always belongs to a parent FunctionParameter object. New FunctionParameter objects can be added to and removed from Function object.
public class Function
    {

        public Function(StringBuilder source
            , int nameStartIndex, int nameEndIndex
            , char enclosingChar
            , FunctionParameter parentParameter
            )
        {
            this.source = source;
            this.nameStartIndex = nameStartIndex;
            this.nameEndIndex = nameEndIndex;
            this.parameters = new List<FunctionParameter>();
            this.enclosingChar = enclosingChar;
            this.parentParameter = parentParameter;



        }


        private FunctionParameter parentParameter;
        public FunctionParameter ParentParameter
        {
            get { return parentParameter; }
        }

        private int nameStartIndex;
        public int NameStartIndex
        {
            get { return nameStartIndex; }
            set
            {
                nameStartIndex = value;

                //Function name shoud be re assigned.
                functionName = null;
            }
        }

        private int nameEndIndex;
        public int NameEndIndex
        {
            get { return nameEndIndex; }
            set
            {
                nameEndIndex = value;

                //Function name shoud be re assigned.
                functionName = null;
            }
        }


        private List<FunctionParameter> parameters;
        public List<FunctionParameter> Parameters
        {
            get { return parameters; }
        }



        private StringBuilder source;
        public StringBuilder Source
        {
            get { return source; }
            set { source = value; }
        }

        private char enclosingChar;
        public char EnclosingChar
        {
            get { return enclosingChar; }
            set
            {
                enclosingChar = value;

                if (parameters.Count > 0)
                {
                    //opening index
                    FunctionParameter firstParam = parameters[0];
                    int openingIndex = (firstParam.EndIndex > firstParam.StartIndex)
                        ? ((firstParam.StartIndex > 0) ? firstParam.StartIndex - 1 : 0)
                          : firstParam.EndIndex;

                    //Closing index
                    FunctionParameter lastParam = parameters[parameters.Count - 1];
                    int closingIndex = (lastParam.EndIndex > lastParam.StartIndex)
                        ? ((lastParam.EndIndex < source.Length - 1) ? lastParam.EndIndex + 1 : source.Length - 1)
                          : lastParam.StartIndex;

                    source[openingIndex] = value;

                    switch (value)
                    {
                        case '[':
                            source[closingIndex] = ']';
                            break;
                        case '{':
                            source[closingIndex] = '}';
                            break;
                        case '(':
                            source[closingIndex] = ')';
                            break;
                        case '<':
                            source[closingIndex] = '>';
                            break;
                        default:
                            source[closingIndex] = value;
                            break;
                    }


                }
            }
        }

        private string functionName;
        public string FunctionName
        {
            get
            {
                if (functionName == null)
                {
                    if (nameStartIndex > nameEndIndex
                        || nameStartIndex < 0
                        || nameEndIndex < 0)
                    {
                        //Function without name
                        functionName = string.Empty;
                    }
                    else
                    {
                        functionName = source.ToString(nameStartIndex
                            , nameEndIndex - nameStartIndex + 1).Trim();
                    }
                }
                return functionName;
            }
            set
            {
                int nameCurrentLength = 0;
                if (nameStartIndex < 0)
                {
                    //Already empty text so no need to remove old text
                    nameStartIndex = 0;
                }
                else if (nameEndIndex > 0)
                {
                    //Remove old text
                    source.Remove(nameStartIndex
                        , nameEndIndex - nameStartIndex + 1);

                    nameCurrentLength = nameEndIndex - nameStartIndex + 1;
                }

                //Insert new text
                source.Insert(nameStartIndex, value);

                //Update endindex
                nameEndIndex = nameStartIndex + value.Length - 1;

                //Assign function name             
                functionName = value.Trim();

                //Offset: subtrace nameCurrentLength from value's length
                int offset = value.Length - nameCurrentLength;

                //Adjust indexes but not of function name.
                AdjustIndexes(offset, true);

            }
        }

        public void RemoveParameter(FunctionParameter parameter)
        {
            int index = parameters.IndexOf(parameter);
            RemoveParameter(index);
        }
        public FunctionParameter RemoveParameter(int index)
        {
            FunctionParameter parameter = parameters[index];
            bool isFirstParam = index == 0;
            bool isLastParam = index == parameters.Count - 1;

            int sourceStartIndex = (isFirstParam)
                ? parameter.StartIndex
                : (parameters[index - 1].EndIndex + 1); //We also need to remove prior comma.

            int sourceEndIndex = (isLastParam)
                ? parameter.EndIndex
                : (parameters[index + 1].StartIndex - 1); //We also need to remove next comma.


            if (sourceEndIndex >= sourceStartIndex)
            {
                int Paramlength = sourceEndIndex - sourceStartIndex + 1;
                source.Remove(sourceStartIndex
                    , Paramlength);

                AdjustIndexes(Paramlength * -1, parameter);
            }

            parameters.RemoveAt(index);

            return parameter;


        }

        public FunctionParameter AddParameter(string parameterText)
        {
            return InsertParameter(parameterText, parameters.Count);
        }

        public FunctionParameter InsertParameter(string parameterText, int index)
        {
            string comma = " , ";

            //index adjustment
            if (index < 0)
            {
                index = 0;
            }
            else if (index > parameters.Count)
            {
                index = parameters.Count;
            }


            bool isFirstParam = index == 0;
            bool isLastParam = index == parameters.Count;


            //Param text for source, it may be with comma
            string textForSource = parameterText;


            int sourceStartIndexForParam;
            int sourceStartIndex;
            if (isFirstParam)
            {
                sourceStartIndexForParam = sourceStartIndex = nameEndIndex + 2; // indext after openning bracket

                if (!isLastParam)
                {
                    textForSource = textForSource + comma; // Ended by a comma
                }
            }
            else
            {
                sourceStartIndex = parameters[index - 1].EndIndex + 1;
                textForSource = comma + textForSource; // Should be started with comma
                sourceStartIndexForParam = sourceStartIndex + comma.Length;
            }

            //Make param object
            FunctionParameter param = new FunctionParameter(source
                , sourceStartIndexForParam
                , sourceStartIndexForParam + parameterText.Length - 1
                , this);

            //Insert into param list
            parameters.Insert(index, param);

            //Insert text into source
            source.Insert(sourceStartIndex, textForSource);

            AdjustIndexes(textForSource.Length, param);

            return param;

        }



        public void AdjustIndexes(int offset)
        {
            AdjustIndexes(offset, null, false);
        }

        public void AdjustIndexes(int offset, bool ownRequest)
        {
            AdjustIndexes(offset, null, ownRequest);
        }

        public void AdjustIndexes(int offset
            , FunctionParameter requestingParam)
        {
            AdjustIndexes(offset, requestingParam, false);
        }
        public void AdjustIndexes(int offset
            , FunctionParameter requestingParam
            , bool ownRequest)
        {
            if (requestingParam == null && !ownRequest)
            {
                nameEndIndex = nameEndIndex + offset;
                nameStartIndex = nameStartIndex + offset;
            }
            else
            {
                //it is requested from either its own argument or itself. 
                //In both cases, function name adjustment is not required.
            }

            //adjustment should be applied only onward params of requeting param
            int index = (requestingParam != null)
                ? parameters.IndexOf(requestingParam) + 1
                : 0;

            for (; index < parameters.Count; index++)
            {
                parameters[index].AdjustIndexes(offset);
            }

            //Also notify parent
            if (requestingParam != null || ownRequest)
            {
                //if request from either child param or itself, only then notification will be required.
                parentParameter.AdjustIndexes(offset, this);
            }
        }

        public override string ToString()
        {
            return FunctionName;
        }
    }


Example

select ISNULL(Convert(datetime , CreatedOn , 103) , getDate()) from Orders.
After parsing above query, system will give a FunctionParameter object with following details
Seq Property Value
1 Statement select ISNULL(Convert(datetime , CreatedOn , 'DD\MM\YYYY') , getDate()) from Orders.
2 ParentFunction [Null]
3 Functions [List]
1.1    FunctionName ISNULL
1.2    ParentFunctionParameter[ Seq# 1]
1.3    FunctionParameters [List]
1.3.1         Statement Convert(datetime , CreatedOn , 'DD\MM\YYYY')
1.3.2         ParentFunction [Seq# 1.1]
1.3.3         Functions [List]
1.3.3.1            FunctionName Convert
1.3.3.2            ParentFunctionParameter[Seq# 1.3.1]
1.3.3.3            FunctionParameters [List]
1.3.3.3.1                 Statement datetime
1.3.3.3.2                 ParentFunction [Seq#  1.3.3.1]
1.3.3.3.3                 Functions [Empty List]
1.3.3.3.4                 Statement CreatedOn
1.3.3.3.5                 ParentFunction [Seq#  1.3.3.1]
1.3.3.3.6                 Functions [Empty List]
1.3.3.3.7                 Statement 103
1.3.3.3.8                 ParentFunction [Seq#  1.3.3.1]
1.3.3.3.9                 Functions [Empty List]
1.3.4         Statement getDate()
1.3.5         ParentFunction [Seq# 1.1]
1.3.6         Functions [List]
1.3.6.1            FunctionName getDate
1.3.6.2            ParentFunctionParameter[Seq# 1.3.4]
1.3.6.3            FunctionParameters [Empty List]

Query Conversion Routine

After getting Function objects , we can easily write a routine for required conversion.
public static string ConvertQuery(SortedList flatListOfFunction
            , StringBuilder source)
        {
            foreach (int key in flatListOfFunction.Keys)
            {
                Function func = flatListOfFunction[key];
                if (func.FunctionName.ToUpper() == "CONVERT")
                {
                    if (func.Parameters.Count == 3)
                    {
                        if (func.Parameters[2].Statement == "103"
                            && func.Parameters[0].Statement.ToUpper() == "DATETIME")
                        {
                            func.FunctionName = "TO_Date";
                            func.RemoveParameter(0);
                            func.Parameters[1].Statement = "'DD/MM/YYYY'";
                        }

                    }
                }

                if (func.FunctionName.ToUpper() == "ISNULL")
                {
                    func.FunctionName = "NVL";
                }

                if (func.FunctionName.ToUpper() == "SUM")
                {
                    func.FunctionName = "Add";
                }
                if (func.FunctionName.ToUpper() == "GETDATE")
                {
                    func.FunctionName = "SysDate";
                    func.EnclosingChar = ' ';
                }
            }

            return source.ToString();

        }
After run query conversion method, above query will modified as follows.
select NVL(To_Date(CreatedOn , 'DD\MM\YYYY') , sysdate) from Orders
read more...