public static FuncDef FindFunction(Context ctx, string name, int nameLength, int args, TEXTENCODE encode, bool createFlag) { Debug.Assert(args >= -2); Debug.Assert(args >= -1 || !createFlag); Debug.Assert(encode == TEXTENCODE.UTF8 || encode == TEXTENCODE.UTF16LE || encode == TEXTENCODE.UTF16BE); int h = (char.ToLowerInvariant(name[0]) + nameLength) % ctx.Funcs.data.Length; // Hash value // First search for a match amongst the application-defined functions. FuncDef best = null; // Best match found so far int bestScore = 0; // Score of best match FuncDef p = FunctionSearch(ctx.Funcs, h, name, nameLength); while (p != null) { int score = MatchQuality(p, args, encode); if (score > bestScore) { best = p; bestScore = score; } p = p.Next; } // If no match is found, search the built-in functions. // // If the SQLITE_PreferBuiltin flag is set, then search the built-in functions even if a prior app-defined function was found. And give // priority to built-in functions. // // Except, if createFlag is true, that means that we are trying to install a new function. Whatever FuncDef structure is returned it will // have fields overwritten with new information appropriate for the new function. But the FuncDefs for built-in functions are read-only. // So we must not search for built-ins when creating a new function. if (createFlag && (best == null || (ctx.Flags & Context.FLAG.PreferBuiltin) != 0)) { FuncDefHash hash = sqlite3GlobalFunctions; bestScore = 0; p = FunctionSearch(hash, h, name, nameLength); while (p != null) { int score = MatchQuality(p, args, encode); if (score > bestScore) { best = p; bestScore = score; } p = p.Next; } } // If the createFlag parameter is true and the search did not reveal an exact match for the name, number of arguments and encoding, then add a // new entry to the hash table and return it. if (createFlag && bestScore < FUNC_PERFECT_MATCH && (best = new FuncDef()) != null) { best.Name = name; best.Args = (short)args; best.PrefEncode = encode; FuncDefInsert(ctx.Funcs, best); } return(best != null && (best.Step != null || best.Func != null || createFlag) ? best : null); }
static FuncDef FunctionSearch(FuncDefHash hash, int h, string func, int funcLength) { for (FuncDef p = hash[h]; p != null; p = p.Hash) { if (p.Name.Length == funcLength && p.Name.StartsWith(func, StringComparison.OrdinalIgnoreCase)) { return(p); } } return(null); }
public static void FuncDefInsert(FuncDefHash hash, FuncDef def) { int nameLength = def.Name.Length; int h = (char.ToLowerInvariant(def.Name[0]) + nameLength) % hash.data.Length; FuncDef other = FunctionSearch(hash, h, def.Name, nameLength); if (other != null) { Debug.Assert(other != def && other.Next != def); def.Next = other.Next; other.Next = def; } else { def.Next = null; def.Hash = hash[h]; hash[h] = def; } }