当前位置:Gxlcms > 数据库问题 > SQLite 自定义函数,聚合,排序规则

SQLite 自定义函数,聚合,排序规则

时间:2021-07-01 10:21:17 帮助过:5人阅读

// // 测试代码 #include <cassert> #include <fstream> #include <iostream> #include <regex> #include <sstream> #include <string> #include "Memory.h" #include "Rand.h" #include "sqlite3.h" using namespace std; //#define OUTPUT_FILE #if defined(OUTPUT_FILE) #define ERR fout << "[" << __func__ << ":" << __LINE__ << "] Error! " #define INFO fout #define DEBUG fout #else #define ERR cerr << "[" << __func__ << ":" << __LINE__ << "] Error! " #define INFO cout #define DEBUG cerr #endif #define MEMINFO(msg) Memory::print(msg) #if defined(OUTPUT_FILE) fstream fout; #endif void initOutputStream() { #if defined(OUTPUT_FILE) fout.open("F:/Sqlite/mysql/log.txt", fstream::ios_base::out | fstream::ios_base::trunc); #endif } void testClean(void* p) { DEBUG << "clean:" << reinterpret_cast<int>(p) << endl; } sqlite3* openDB(const string& file) { sqlite3* db{}; int ret = sqlite3_open_v2(file.c_str(), &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, 0); if (SQLITE_OK != ret) { ERR << "sqlite3_open_v2 failed." << endl; return nullptr; } return db; } bool closeDB(sqlite3* db) { int ret = sqlite3_close_v2(db); if (SQLITE_OK != ret) { ERR << "sqlite3_close_v2 failed." << endl; return false; } return true; } bool execSQL(sqlite3* db, const string& sql) { char* errmsg{}; int ret = sqlite3_exec(db, sql.c_str(), 0, 0, &errmsg); if (SQLITE_OK != ret) { ERR << "sqlite3_exec failed." << errmsg << endl; } sqlite3_free(errmsg); return SQLITE_OK == ret; } bool printSQL(sqlite3* db, const string& sql) { int ret{}; sqlite3_stmt* stmt{}; ret = sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt, 0); if (SQLITE_OK != ret) { ERR << "sqlite3_prepare_v2 failed." << sqlite3_errmsg(db) << endl; return false; } INFO << sql << endl; int colCount = sqlite3_column_count(stmt); if (colCount > 0) { for (int col = 0; col < colCount; ) { INFO << sqlite3_column_name(stmt, col); if (++col != colCount) { INFO << \t; } } INFO << endl; } do { ret = sqlite3_step(stmt); if (SQLITE_ROW != ret) { break; } for (int col = 0; col < colCount; ) { const char* text = reinterpret_cast<const char*>(sqlite3_column_text(stmt, col)); INFO << (text ? text : ""); if (++col != colCount) { INFO << \t; } } INFO << endl; } while (true); if (SQLITE_DONE != ret) { ERR << "sqlite3_step failed." << sqlite3_errmsg(db) << endl; } ret = sqlite3_finalize(stmt); if (SQLITE_OK != ret) { ERR << "sqlite3_finalize failed." << sqlite3_errmsg(db) << endl; return false; } return true; } // SQLite 函数 void echo(sqlite3_context* ctx, int argc, sqlite3_value** argv) { assert(1 == argc); // DEBUG << "user data:" << reinterpret_cast<int>(sqlite3_user_data(ctx)) << endl; const char* text{reinterpret_cast<const char*>(sqlite3_value_text(argv[0]))}; sqlite3_result_text(ctx, text, -1, 0); } void strcat_column(sqlite3_context* ctx, int argc, sqlite3_value** argv) { const char* delimiter{"\t"}; const int DELIMITER_LEN = strlen(delimiter); int len = 0; for (int i = 0; i < argc; ++i) { len += sqlite3_value_bytes(argv[i]); len += DELIMITER_LEN; } char* buf = static_cast<char*>(sqlite3_malloc(len)); int pos = 0; for (int i = 0; i < argc; ) { int bytes = sqlite3_value_bytes(argv[i]); memcpy(buf + pos, sqlite3_value_blob(argv[i]), bytes); pos += bytes; if (++i != argc) { memcpy(buf + pos, delimiter, DELIMITER_LEN); pos += DELIMITER_LEN; } } buf[pos] = 0; sqlite3_result_text(ctx, buf, -1, 0); } // SQLite 聚合函数 struct AggregateCharData { int len{}; char* buf{}; }; void strcat_step(sqlite3_context* ctx, int argc, sqlite3_value** argv) { assert(2 == argc); AggregateCharData* pData{static_cast<AggregateCharData*>(sqlite3_aggregate_context(ctx, sizeof(AggregateCharData)))}; if (!pData) { ERR << "Alloc AggregateData failed!" << endl; return; } int valueLen = sqlite3_value_bytes(argv[0]); if (!pData->buf) { pData->buf = static_cast<char*>(sqlite3_malloc(valueLen + 1)); } else { int delimiterLen = sqlite3_value_bytes(argv[1]); int len = valueLen + delimiterLen + pData->len + 1; pData->buf = static_cast<char*>(sqlite3_realloc(pData->buf, len)); memcpy(pData->buf + pData->len, sqlite3_value_blob(argv[1]), delimiterLen); pData->len += delimiterLen; } memcpy(pData->buf + pData->len, sqlite3_value_blob(argv[0]), valueLen); pData->len += valueLen; } void strcat_final(sqlite3_context* ctx) { AggregateCharData* pData{static_cast<AggregateCharData*>(sqlite3_aggregate_context(ctx, sizeof(AggregateCharData)))}; if (!pData || !pData->buf) { sqlite3_result_text(ctx, pData->buf, pData->len, sqlite3_free); } } /** * SQLite 排序示例,将值拆分成非全数字组成的前缀,和全数字组成的后缀,前缀不同时,按字典排序;前缀相同时,后缀按数字大小排序 **/ int compareName(void*, int lhsLen, const void* lhsData, int rhsLen, const void* rhsData) { string lText(static_cast<const char*>(lhsData), 0, lhsLen); string rText(static_cast<const char*>(rhsData), 0, rhsLen); regex reg("^(.*[^\\d]+)(\\d+)$|^(\\d+)$"); smatch lMatch; smatch rMatch; if (!regex_match(lText, lMatch, reg) || !regex_match(rText, rMatch, reg)) { return 0; } string lPrefix = lMatch.str(1); string lSuffix = lPrefix.empty() ? lMatch.str(3) : lMatch.str(2); string rPrefix = rMatch.str(1); string rSuffix = rPrefix.empty() ? rMatch.str(3) : rMatch.str(2); if (lPrefix != rPrefix) { return lPrefix.compare(rPrefix); } // 过滤后缀前面的字符0 static const string POSITIVE_NUMBER {"123456789"}; size_t pos = lSuffix.find_first_of(POSITIVE_NUMBER); if (string::npos != pos && 0 != pos) { lSuffix = lSuffix.substr(pos); } pos = rSuffix.find_first_of(POSITIVE_NUMBER); if (string::npos != pos && 0 != pos) { rSuffix = rSuffix.substr(pos); } // DEBUG << "suffix:" << lSuffix << "/" << lText << ", " << rSuffix << "/" << rText << endl; int lSuffixLen = lSuffix.length(); int rSuffixLen = rSuffix.length(); if (lSuffixLen != rSuffixLen) { return lSuffixLen - rSuffixLen; } for (int i = 0; i < lSuffixLen; ++i) { if (lSuffix.at(i) != rSuffix.at(i)) { return lSuffix.at(i) - rSuffix.at(i); } } return 0; } string randNumString() { static const string NUMBERS{"012345678900"}; string ret; int len = Rand::rand(3, 10); for (int i = 0; i < len; ++i) { ret.push_back(NUMBERS.at(Rand::rand(0, NUMBERS.length() - 1))); } return ret; } string randPrefix() { static const string PREFIX_STR{"01234567890123456789012345678901234567890123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-"}; string ret; int len = Rand::rand(3, 8); for (int i = 0; i < len; ++i) { ret.push_back(PREFIX_STR.at(Rand::rand(0, PREFIX_STR.length() - 1))); } return ret; } void insertTestData(sqlite3* db) { execSQL(db, "INSERT INTO Foo VALUES(null, 1, 2);"); execSQL(db, "INSERT INTO Foo VALUES(null, 10.5, 20.1);"); execSQL(db, "INSERT INTO Foo VALUES(null, ‘abc‘, ‘hehe‘);"); vector<string> prefixs{randPrefix(), randPrefix(), randPrefix(), randPrefix()}; ostringstream stm; for (int i = 0; i < 30; ++i) { string prefix = prefixs.at(Rand::rand(0, prefixs.size() - 1)); stm.str(""); stm << "INSERT INTO Foo VALUES(null, ‘" << prefix << randNumString() << "‘, " << Rand::rand(1, 999) << ");"; execSQL(db, stm.str()); stm.str(""); stm << "INSERT INTO Foo VALUES(null, ‘" << prefix << randNumString() << "‘, " << Rand::rand(1, 999) << ");"; execSQL(db, stm.str()); stm.str(""); stm << "INSERT INTO Foo VALUES(null, ‘" << prefix << randNumString() << "‘, " << Rand::rand(1, 999) << ");"; execSQL(db, stm.str()); } } int main(int, char**) { initOutputStream(); MEMINFO("start"); sqlite3* db = openDB("Foo.db"); int ret{}; MEMINFO("create table"); execSQL(db, "CREATE TABLE IF NOT EXISTS Foo" "(_id INTEGER PRIMARY KEY, name TEXT, info TEXT);"); // insertTestData(db); MEMINFO("query all"); printSQL(db, "SELECT * FROM Foo;"); MEMINFO("set echo"); ret = sqlite3_create_function_v2(db, "echo", 1, SQLITE_UTF8, reinterpret_cast<void*>(1), echo, 0, 0, testClean); if (SQLITE_OK != ret) { ERR << "sqlite3_create_function_v2 -> echo." << sqlite3_errmsg(db) << endl; } MEMINFO("query using echo"); printSQL(db, "SELECT echo(‘Hello SQLite!‘) AS replay;"); printSQL(db, "SELECT _id, echo(name) AS name FROM Foo;"); MEMINFO("set strcat_column"); ret = sqlite3_create_function_v2(db, "strcat_column", -1, SQLITE_UTF8, 0, strcat_column, 0, 0, 0); if (SQLITE_OK != ret) { ERR << "sqlite3_create_function_v2 -> strcat_column." << sqlite3_errmsg(db) << endl; } MEMINFO("query using strcat_column"); printSQL(db, "SELECT strcat_column(_id, name, info) AS list FROM Foo;"); MEMINFO("set strcat"); ret = sqlite3_create_function_v2(db, "strcat", 2, SQLITE_UTF8, 0, 0, strcat_step, strcat_final, 0); MEMINFO("query using strcat"); if (SQLITE_OK != ret) { ERR << "sqlite3_create_function_v2 -> strcat_column." << sqlite3_errmsg(db) << endl; } printSQL(db, "SELECT strcat(_id, ‘,‘) AS ids FROM Foo;"); printSQL(db, "SELECT strcat(name, ‘,‘) AS names FROM Foo;"); printSQL(db, "SELECT strcat(info, ‘,‘) AS infos FROM Foo;"); MEMINFO("set compareName"); ret = sqlite3_create_collation_v2(db, "compareName", SQLITE_UTF8, reinterpret_cast<void*>(2), compareName, testClean); MEMINFO("query using compareName"); if (SQLITE_OK != ret) { ERR << "sqlite3_create_collation_v2 -> compareName." << sqlite3_errmsg(db) << endl; } printSQL(db, "SELECT * FROM Foo ORDER BY name collate compareName;"); MEMINFO("close db"); closeDB(db); MEMINFO("end"); return 0; }

 

//////////////////////////////////////////////////////////////////////////
// 随机数

#ifndef RAND_H
#define RAND_H

#include <random>


class Rand
{
public:
    static int rand(int minValue, int maxValue);

private:
    static std::default_random_engine DEFAULT_ENGINE;
};

#endif // RAND_H
    
    
#include "Rand.h"
#include <ctime>


std::default_random_engine Rand::DEFAULT_ENGINE(time(0));

int Rand::rand(int minValue, int maxValue)
{
    std::uniform_int_distribution<int> d(minValue, maxValue);
    return d(DEFAULT_ENGINE);
}

 

//////////////////////////////////////////////////////////////////////////
// 内存打印工具

#ifndef MEMORY_H
#define MEMORY_H

#include <string>

using std::string;


class Memory
{
public:
    static void print(const string& tag = "");

private:
    static string format(long long);
    static long long m_prevAvaiPhys;
};

#endif // MEMORY_H


#include "Memory.h"
#include <iostream>
#include <sstream>
#include "windows.h"


long long Memory::m_prevAvaiPhys{};

void Memory::print(const string& tag)
{
    MEMORYSTATUSEX mem{};
    mem.dwLength = sizeof(MEMORYSTATUSEX);
    GlobalMemoryStatusEx(&mem);
    std::cout << "virtual:" << format(mem.ullAvailVirtual) << "/" << format(mem.ullTotalVirtual)
              << " physical:" << format(mem.ullAvailPhys) << "/" << format(mem.ullTotalPhys);

    if (0 != m_prevAvaiPhys)
    {
        std::cout << ", reduce physical:" << (long long)(m_prevAvaiPhys - mem.ullAvailPhys) << "B";
    }
    m_prevAvaiPhys = mem.ullAvailPhys;

    std::cout << " [" << tag <<  "]" << std::endl;
}

string Memory::format(long long bytes)
{
    std::ostringstream stm;
    //stm << (bytes >> 20) << "MB";
    stm << (bytes >> 10) << "KB";
    return stm.str();
}

 

SQLite 自定义函数,聚合,排序规则

标签:output   fun   完成后   mysql   pac   memcpy   reg   realloc   names   

人气教程排行