/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2017 Peter Powell * Copyright (C) 2010 Daniel De Graaf * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once namespace SQL { class Error; class Field; class Provider; class Query; class Result; /** A list of parameter replacement values. */ typedef std::vector ParamList; /** A map of parameter replacement values. */ typedef std::map ParamMap; /** A list of SQL fields from a specific row. */ typedef std::vector Row; /** An enumeration of possible error codes. */ enum ErrorCode { /** No error has occurred. */ SUCCESS, /** The database identifier is invalid. */ BAD_DBID, /** The database connection has failed. */ BAD_CONN, /** Executing the query failed. */ QSEND_FAIL, /** Reading the response failed. */ QREPLY_FAIL }; /** Populates a parameter map with information about a user. * @param user The user to collect information from. * @param userinfo The map to populate. */ void PopulateUserInfo(User* user, ParamMap& userinfo); } /** Represents a single SQL field. */ class SQL::Field { private: /** Whether this SQL field is NULL. */ bool null; /** The underlying SQL value. */ std::string value; public: /** Creates a new NULL SQL field. */ Field() : null(true) { } /** Creates a new non-NULL SQL field. * @param v The value of the field. */ Field(const std::string& v) : null(false) , value(v) { } /** Determines whether this SQL entry is NULL. */ inline bool IsNull() const { return null; } /** Retrieves the underlying value. */ inline operator const std::string&() const { return value; } }; /** Represents the result of an SQL query. */ class SQL::Result : public classbase { public: /** * Return the number of rows in the result. * * Note that if you have perfomed an INSERT or UPDATE query or other * query which will not return rows, this will return the number of * affected rows. In this case you SHOULD NEVER access any of the result * set rows, as there aren't any! * @returns Number of rows in the result set. */ virtual int Rows() = 0; /** Retrieves the next available row from the database. * @param result A list to store the fields from this row in. * @return True if a row could be retrieved; otherwise, false. */ virtual bool GetRow(Row& result) = 0; /** Retrieves a list of SQL columns in the result. * @param result A reference to the vector to store column names in. */ virtual void GetCols(std::vector& result) = 0; }; /** SQL::Error holds the error state of a request. * The error string varies from database software to database software * and should be used to display informational error messages to users. */ class SQL::Error { private: /** The custom error message if one has been specified. */ const std::string message; public: /** The code which represents this error. */ const ErrorCode code; /** Initialize an SQL::Error from an error code. * @param c A code which represents this error. */ Error(ErrorCode c) : code(c) { } /** Initialize an SQL::Error from an error code and a custom error message. * @param c A code which represents this error. * @param m A custom error message. */ Error(ErrorCode c, const std::string m) : message(m) , code(c) { } /** Retrieves the error message. */ const char* ToString() const { if (!message.empty()) return message.c_str(); switch (code) { case BAD_DBID: return "Invalid database identifier"; case BAD_CONN: return "Invalid connection"; case QSEND_FAIL: return "Sending query failed"; case QREPLY_FAIL: return "Getting query result failed"; default: return "Unknown error"; } } }; /** * Object representing an SQL query. This should be allocated on the heap and * passed to an SQL::Provider, which will free it when the query is complete or * when the querying module is unloaded. * * You should store whatever information is needed to have the callbacks work in * this object (UID of user, channel name, etc). */ class SQL::Query : public classbase { protected: /** Creates a new SQL query. */ Query(Module* Creator) : creator(Creator) { } public: const ModuleRef creator; /* Destroys this Query instance. */ virtual ~Query() { } /** Called when an SQL error happens. * @param error The error that occurred. */ virtual void OnError(Error& error) = 0; /** Called when a SQL result is received. * @param result The result of the SQL query. */ virtual void OnResult(Result& result) = 0; }; /** * Provider object for SQL servers */ class SQL::Provider : public DataProvider { public: Provider(Module* Creator, const std::string& Name) : DataProvider(Creator, Name) { } /** Submit an asynchronous SQL query. * @param callback The result reporting point * @param query The hardcoded query string. If you have parameters to substitute, see below. */ virtual void Submit(Query* callback, const std::string& query) = 0; /** Submit an asynchronous SQL query. * @param callback The result reporting point * @param format The simple parameterized query string ('?' parameters) * @param p Parameters to fill in for the '?' entries */ virtual void Submit(Query* callback, const std::string& format, const SQL::ParamList& p) = 0; /** Submit an asynchronous SQL query. * @param callback The result reporting point * @param format The parameterized query string ('$name' parameters) * @param p Parameters to fill in for the '$name' entries */ virtual void Submit(Query* callback, const std::string& format, const ParamMap& p) = 0; }; inline void SQL::PopulateUserInfo(User* user, ParamMap& userinfo) { userinfo["nick"] = user->nick; userinfo["host"] = user->GetRealHost(); userinfo["ip"] = user->GetIPString(); userinfo["gecos"] = user->fullname; userinfo["ident"] = user->ident; userinfo["server"] = user->server->GetName(); userinfo["uuid"] = user->uuid; }