001package gudusoft.gsqlparser.sqlenv;
002
003import gudusoft.gsqlparser.nodes.TTypeName;
004import gudusoft.gsqlparser.util.SQLUtil;
005
006import java.util.*;
007
008/**
009 * SQL function
010 */
011public class TSQLFunction extends TSQLProcedure {
012
013    public TSQLFunction(TSQLSchema sqlSchema, String functionName){
014        super(sqlSchema,functionName,ESQLDataObjectType.dotFunction);
015    }
016
017    public TSQLFunction(TSQLOraclePackage oraclePackage, String functionName) {
018        super(oraclePackage, functionName, ESQLDataObjectType.dotFunction);
019    }
020
021
022    // volatile: routine metadata written during registration (TMetadataCollector)
023    // and read lock-free by resolver helpers on other threads
024    private volatile TTypeName returnType;
025
026    public void setReturnType(TTypeName returnType) {
027        this.returnType = returnType;
028    }
029
030    public TTypeName getReturnType() {
031        return returnType;
032    }
033
034    /**
035     * column list
036     * @return a column list
037     */
038    public List<TFunctoinColumn> getColumnsInReturnTable() {
039        return columnsInReturnTable();
040    }
041
042    // No field initializer + volatile: the TSQLSchemaObject constructor publishes
043    // `this` into shared env indexes before subclass initializers run, and concurrent
044    // analyzers registering the same function share this instance. COW list keeps
045    // external iteration (getColumnsInReturnTable callers) safe against appends.
046    private volatile java.util.concurrent.CopyOnWriteArrayList<TFunctoinColumn> columnsInReturnTable;
047
048    private java.util.concurrent.CopyOnWriteArrayList<TFunctoinColumn> columnsInReturnTable() {
049        java.util.concurrent.CopyOnWriteArrayList<TFunctoinColumn> l = columnsInReturnTable;
050        if (l == null) {
051            synchronized (this) {
052                if (columnsInReturnTable == null) {
053                    columnsInReturnTable = new java.util.concurrent.CopyOnWriteArrayList<TFunctoinColumn>();
054                }
055                l = columnsInReturnTable;
056            }
057        }
058        return l;
059    }
060
061    /**
062     * add a new column to the table
063     *
064     * @param columnName column name
065     */
066    public void addReturnColumn(String columnName){
067        java.util.concurrent.CopyOnWriteArrayList<TFunctoinColumn> l = columnsInReturnTable();
068        // search-then-add must be atomic under concurrent registration
069        synchronized (l) {
070            if (!searchColumnInReturnTable(columnName)){
071                l.add(new TFunctoinColumn(this,columnName));
072            }
073        }
074    }
075
076    public boolean searchColumnInReturnTable(String columnName){
077        boolean isFound = false;
078
079        for(TFunctoinColumn s : columnsInReturnTable()){
080            if (s.compareTo(columnName) == 0){
081                isFound = true;
082                break;
083            }
084        }
085
086        return isFound;
087    }
088
089    @Override
090    public String toString(){
091        StringBuilder sb = new StringBuilder();
092        sb.append(getName().toString());
093        sb.append("\n\t\t\tparameters:");
094        for(TSQLParameter p: getParameterList()){
095            sb.append("\n\t\t\t\t"+p.getName()+",\t"+p.getParameterType().toString());
096        }
097        if (getReturnType() != null){
098            sb.append("\n\t\t\t return type:"+getReturnType().toString());
099        }
100
101
102        return sb.toString();
103    }
104
105}