我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
专题:一个自制代码生成器(嵌入式脚本语言)之总述-CSDN博客
专题:一个自制代码生成器(嵌入式脚本语言)之对象模型-CSDN博客
专题:一个自制代码生成器(嵌入式脚本语言)之堆栈结构和总入口-CSDN博客
专题:一个自制代码生成器(嵌入式脚本语言)之核心逻辑-CSDN博客
专题:一个自制代码生成器(嵌入式脚本语言)之辅助逻辑-CSDN博客
专题:一个自制代码生成器(嵌入式脚本语言)之应用实例-CSDN博客(本篇)
专题:一个自制代码生成器(嵌入式脚本语言)之模型开发-CSDN博客
专题:一个自制代码生成器(嵌入式脚本语言)之代码模板详解-CSDN博客
目录
[2.1 创建模型](#2.1 创建模型)
[2.2 生成代码](#2.2 生成代码)
[2.3 生成的代码](#2.3 生成的代码)
一、数据库模型
数据库模型是根据数据库定义生成数据库操作相关代码的模型,生成的代码是静态代码,具有静态代码的编译时检查和运行效率。
数据库模型支持表定义、主键、定制的DML操作。对于C++客户代码,所有操作都是基于函数的,函数名和参数清晰地表达了函数的功能。
下面我们先了解一个应用实例,然后再研究如何编写模型。
二、应用实例
2.1 创建模型
cpp
bool Rooster_AddAllTable(CCTModel_UniversalDB* pCTM)
{
CCTModel_UniversalDB::table* p;
//资源类型,预定义的数值
p = pCTM->AddNewTable("RESOURCE_TYPE_D", "资源类型");
if (NULL == p)return false;
p->AddMember("RESOURCE_TYPE_ID", "long", "资源类型");
p->AddMember("COMMENT", "string", "备注");
p->SetPK("RESOURCE_TYPE_ID");
p->AddDML("InsertNewResourceType", "insert", "RESOURCE_TYPE_ID,COMMENT", "", "插入新资源类型");
//资源使用类型,预定义的数值
p = pCTM->AddNewTable("RESOURCE_USE_TYPE_D", "资源使用类型");
if (NULL == p)return false;
p->AddMember("RESOURCE_USE_TYPE_ID", "long", "资源使用类型ID");
p->AddMember("COMMENT", "string", "备注");
p->SetPK("RESOURCE_USE_TYPE_ID");
p->AddDML("InsertNewResourceUseType", "insert", "RESOURCE_USE_TYPE_ID,COMMENT", "", "插入新资源使用类型");
//资源
p = pCTM->AddNewTable("RESOURCE_D", "资源");
if (NULL == p)return false;
p->AddMember("RESOURCE_ID", "long", "资源ID");
p->AddMember("RESOURCE_NAME", "string", "资源名称");
p->AddMember("RESOURCE_TYPE_ID", "long", "资源类型");
p->AddMember("RESOURCE_WITH_SYS", "long", "资源是否区分sys/sys2");
p->AddMember("COMMENT", "string", "备注");
p->SetPK("RESOURCE_ID");
p->AddDML("InsertNewResource", "insert", "*", "", "插入新资源");
p->AddDML("GetAllResource", "select", "*", "", "获得全部");
//任务定义
p = pCTM->AddNewTable("TASK_D", "任务");
if (NULL == p)return false;
p->AddMember("TASK_ID", "long", "任务ID");
p->AddMember("TASK_NAME", "string", "任务名称");
p->AddMember("TASK_MULTIPLE", "long", "0非多开1多开");
p->AddMember("TASK_WITH_SYS", "long", "是否区分sys/sys2");
p->AddMember("TASK_PRIORITY", "long", "优先级,小的优先");
p->AddMember("TASK_PLAN_TIME", "string", "执行时间,'2,8-16',时间点或时间段");
p->AddMember("TASK_PLAN_INTERVAL", "long", "执行时间段的执行间隔(分钟0-59)");
p->AddMember("TASK_START_CMD", "string", "启动命令");
p->AddMember("COMMENT", "string", "备注");
p->SetPK("TASK_ID");
p->AddDML("InsertNewTaskDefine", "insert", "*", "", "插入新任务定义");
p->AddDML("GetAllTask", "select", "*", "", "获得全部");
//任务资源使用定义
p = pCTM->AddNewTable("TASK_RESOURCE_USE_D", "任务资源使用");
if (NULL == p)return false;
p->AddMember("TASK_ID", "long", "任务ID");
p->AddMember("RESOURCE_ID", "long", "资源ID");
p->AddMember("RESOURCE_USE_TYPE_ID", "long", "资源使用类型ID");
p->AddMember("COMMENT", "string", "备注");
p->SetPK("TASK_ID,RESOURCE_ID");
p->AddDML("InsertNewTaskResurceUseDefine", "insert", "TASK_ID,RESOURCE_ID,RESOURCE_USE_TYPE_ID,COMMENT", "", "插入新任务资源使用定义");
p->AddDML("GetAllTaskResourceUse", "select", "*", "", "获得全部");
//任务队列表
p = pCTM->AddNewTable("TASK_QUEUE", "待执行的任务队列");
if (NULL == p)return false;
p->AddMember("TASK_ID", "long", "任务ID");
p->AddMember("SYS", "long", "维度1");
p->AddMember("SYS2", "long", "维度2");
p->AddMember("TASK_NAME", "string", "任务名称(参考)");
p->AddMember("TASK_PRIORITY", "long", "优先级,小的优先(参考)");
p->AddMember("COMMENT", "string", "备注(参考)");
p->AddMember("INSERT_TIME", "time", "开始时间", "", "TIME_LOG");
p->SetPK("TASK_ID,SYS,SYS2");
p->AddDML("InsertNewTaskQueue", "insert", "TASK_ID,SYS,SYS2,TASK_NAME,TASK_PRIORITY,COMMENT,INSERT_TIME", "", "插入新任务队列");
p->AddDML("DeleteTaskQueue", "delete", "", "TASK_ID,SYS,SYS2", "删除任务队列");
p->AddDML("GetAllTaskQueue", "select", "*", "", "获取全部任务队列");
p->AddDML("GetTaskQueue", "select", "*", "TASK_ID,SYS,SYS2", "获取任务队列");
//任务执行表
p = pCTM->AddNewTable("TASK_LOG", "任务日志");
if (NULL == p)return false;
p->AddMember("TASK_LOG_ID", "long", "任务执行序列号SEQ_TASK_LOG");
p->AddMember("TASK_ID", "long", "任务ID");
p->AddMember("SYS", "long", "维度1");
p->AddMember("SYS2", "long", "维度2");
p->AddMember("PID", "long", "任务所在的进程,客户方写入");
p->AddMember("START_TIME", "time", "开始时间", "", "TIME_LOG");
p->AddMember("FINISH_TIME", "time", "结束时间", "", "TIME_LOG");
p->AddMember("RETURN_VALUE", "long", "返回值 0成功 <0Rooster错误 >0任务错误");
p->AddMember("UPDATE_TIME", "time", "记录更新时间", "", "TIME_LOG");
p->SetPK("TASK_LOG_ID");
p->AddDML("InsertNewTaskLog", "insert", "TASK_LOG_ID,TASK_ID,SYS,SYS2,START_TIME,UPDATE_TIME", "", "插入新任务日志");
p->AddDML("UpdateTaskLog", "update", "PID,UPDATE_TIME", "TASK_LOG_ID", "更新任务日志", "finish_time=0");
p->AddDML("FinishTaskLog", "update", "FINISH_TIME,RETURN_VALUE,UPDATE_TIME", "TASK_LOG_ID", "更新任务日志", "finish_time=0");
p->AddDML("GetCurrentTask", "select", "*", "", "获取正在运行的任务", "finish_time=0");
//序列
if (NULL == pCTM->AddNewSequence("SEQ_TASK_LOG", "TASK日志序列", 0))return false;
return true;
}
这个代码创建了一组表和一个序列,每一行代码的功能都是显而易见的。
2.2 生成代码
cpp
int main(int argc, char** argv)
{
if (!InitActiveApp("CCTModel_UniversalDB", 1024 * 1024, argc, argv))exit(1);
if (sizeof(long) != 8)
{
thelog << "非64位程序!" << ende;
}
G_IS_DEBUG = true;
CCTModel_UniversalDB ctm;
if (!Rooster_AddAllTable(&ctm))
{
thelog << "执行失败" << ende;
return __LINE__;
}
if (!ctm.CreateCode("ns_rooster_struct", "RoosterStruct", "."))
{
thelog << "执行失败" << ende;
return __LINE__;
}
thelog << "程序退出" << endi;
return 0;
}
有用的就两句:Rooster_AddAllTable创建模型,CreateCode生成代码。
2.3 生成的代码
生成的一组文件:
总入口头文件是_cc_CRoosterStruct.h:
cpp
//_cc_CRoosterStruct.h 自动生成的代码
//
// Copyright (c) ct All rights reserved.
// 版权所有 ct 保留所有权利
//
//警告:本文件由CT系统自动生成,不可手工修改
#ifndef CTFC_RoosterStruct_H
#define CTFC_RoosterStruct_H 1
//如果需要使用内存数据库直连功能,请在包含本头文件之前定义 CTFC_RoosterStruct_H_SHM_DB
//如果需要使用MariaDB功能,请在包含本头文件之前定义 CTFC_RoosterStruct_H_MARIA_DB
#include "_cc_RoosterStruct_RESOURCE_TYPE_D.h"
#include "_cc_RoosterStruct_RESOURCE_USE_TYPE_D.h"
#include "_cc_RoosterStruct_RESOURCE_D.h"
#include "_cc_RoosterStruct_TASK_D.h"
#include "_cc_RoosterStruct_TASK_RESOURCE_USE_D.h"
#include "_cc_RoosterStruct_TASK_QUEUE.h"
#include "_cc_RoosterStruct_TASK_LOG.h"
#include "_cc_RoosterStruct_SEQ_TASK_LOG.h"
using namespace ns_my_std;
namespace ns_rooster_struct
{
class CShmDB_RoosterStruct
{
public:
//表
CRoosterStruct_RESOURCE_TYPE_D m_RESOURCE_TYPE_D;//资源类型
CRoosterStruct_RESOURCE_USE_TYPE_D m_RESOURCE_USE_TYPE_D;//资源使用类型
CRoosterStruct_RESOURCE_D m_RESOURCE_D;//资源
CRoosterStruct_TASK_D m_TASK_D;//任务
CRoosterStruct_TASK_RESOURCE_USE_D m_TASK_RESOURCE_USE_D;//任务资源使用
CRoosterStruct_TASK_QUEUE m_TASK_QUEUE;//待执行的任务队列
CRoosterStruct_TASK_LOG m_TASK_LOG;//任务日志
//序列
CRoosterStruct_SEQ_TASK_LOG m_SEQ_TASK_LOG;//TASK日志序列
public:
#ifdef CTFC_RoosterStruct_H_SHM_DB
#define CTFC_RoosterStruct_H_WITH_DB
typedef CShmDB T_DB;
#endif
#ifdef CTFC_RoosterStruct_H_MARIA_DB
#define CTFC_RoosterStruct_H_WITH_DB
typedef CMariaDB T_DB;
#endif
private:
#ifdef CTFC_RoosterStruct_H_WITH_DB
T_DB m_ShmDB;
T_DB * pDB;
#endif
public:
#ifdef CTFC_RoosterStruct_H_WITH_DB
//返回内部数据库对象
T_DB * getDB(){return pDB;}
//直连初始化
bool DBInit(char const * db = nullptr)
{
#ifdef CTFC_RoosterStruct_H_SHM_DB
CShmActiveObjects * p;
p = m_ShmDB.GetCShmActiveObjects();
if (!p->isConnected() && !p->Attach(false))
#endif
#ifdef CTFC_RoosterStruct_H_MARIA_DB
if(!m_ShmDB.Connect(db))
#endif
{
thelog << "CRoosterStruct连接失败" << ende;
return false;
}
DEBUG_LOG << "CRoosterStruct连接成功" << endi;
pDB = &m_ShmDB;
m_RESOURCE_TYPE_D.Init(pDB);
m_RESOURCE_USE_TYPE_D.Init(pDB);
m_RESOURCE_D.Init(pDB);
m_TASK_D.Init(pDB);
m_TASK_RESOURCE_USE_D.Init(pDB);
m_TASK_QUEUE.Init(pDB);
m_TASK_LOG.Init(pDB);
m_SEQ_TASK_LOG.Init(pDB);
return true;
}
//直连断开
bool DBUnInit()
{
#ifdef CTFC_RoosterStruct_H_SHM_DB
CShmActiveObjects * p;
p = m_ShmDB.GetCShmActiveObjects();
if (p->isConnected())p->Detach();
#endif
#ifdef CTFC_RoosterStruct_H_MARIA_DB
pDB->Close();
#endif
pDB = NULL;
return true;
}
//直连创建所有数据库对象
bool DBCreateAllDBObject()
{
//创建表
if(!m_RESOURCE_TYPE_D.CreateTable())return false;
if(!m_RESOURCE_USE_TYPE_D.CreateTable())return false;
if(!m_RESOURCE_D.CreateTable())return false;
if(!m_TASK_D.CreateTable())return false;
if(!m_TASK_RESOURCE_USE_D.CreateTable())return false;
if(!m_TASK_QUEUE.CreateTable())return false;
if(!m_TASK_LOG.CreateTable())return false;
//创建序列
if(!m_SEQ_TASK_LOG.CreateSequence())return false;
return true;
}
//直连显示所有数据库对象
bool DBShowAllDBObject()
{
//显示表
if(!m_RESOURCE_TYPE_D.Show())return false;
if(!m_RESOURCE_USE_TYPE_D.Show())return false;
if(!m_RESOURCE_D.Show())return false;
if(!m_TASK_D.Show())return false;
if(!m_TASK_RESOURCE_USE_D.Show())return false;
if(!m_TASK_QUEUE.Show())return false;
if(!m_TASK_LOG.Show())return false;
//显示序列
thelog << "sequence:" << endl << "-------------------------" << endl;
theLog<< "SEQ_TASK_LOG " << m_SEQ_TASK_LOG.GetSequenceValue() << endl;
theLog << "-------------------------" << endi;
return true;
}
#endif
};
}
#endif
这个文件看起来和普通手写的文件没有任何区别,除了它真的是用代码模板生成的。
再来看看生成这个文件的模板_t_UniversalDB.h.ct是什么样的:
cpp
//_cc_C${SYS}.h 自动生成的代码
//
// Copyright (c) ct All rights reserved.
// 版权所有 ct 保留所有权利
//
//警告:本文件由CT系统自动生成,不可手工修改
#ifndef CTFC_${SYS}_H
#define CTFC_${SYS}_H 1
//如果需要使用内存数据库直连功能,请在包含本头文件之前定义 CTFC_${SYS}_H_SHM_DB
//如果需要使用MariaDB功能,请在包含本头文件之前定义 CTFC_${SYS}_H_MARIA_DB
<%foreach table in ${tables}%>
#include "_cc_${SYS}_${table}.h"
<%endforeach%>
<%foreach sequence in sequences%>
#include "_cc_${SYS}_${sequence}.h"
<%endforeach%>
using namespace ns_my_std;
namespace ${NAMESPACE}
{
class CShmDB_${SYS}
{
public:
//表
<%foreach table in tables%>
C${SYS}_${table} m_${table};//${table.comment}
<%endforeach%>
//序列
<%foreach sequence in sequences%>
C${SYS}_${sequence} m_${sequence};//${sequence.comment}
<%endforeach%>
public:
#ifdef CTFC_${SYS}_H_SHM_DB
#define CTFC_${SYS}_H_WITH_DB
typedef CShmDB T_DB;
#endif
#ifdef CTFC_${SYS}_H_MARIA_DB
#define CTFC_${SYS}_H_WITH_DB
typedef CMariaDB T_DB;
#endif
private:
#ifdef CTFC_${SYS}_H_WITH_DB
T_DB m_ShmDB;
T_DB * pDB;
#endif
public:
#ifdef CTFC_${SYS}_H_WITH_DB
//返回内部数据库对象
T_DB * getDB(){return pDB;}
//直连初始化
bool DBInit(char const * db = nullptr)
{
#ifdef CTFC_${SYS}_H_SHM_DB
CShmActiveObjects * p;
p = m_ShmDB.GetCShmActiveObjects();
if (!p->isConnected() && !p->Attach(false))
#endif
#ifdef CTFC_${SYS}_H_MARIA_DB
if(!m_ShmDB.Connect(db))
#endif
{
thelog << "C${SYS}连接失败" << ende;
return false;
}
DEBUG_LOG << "C${SYS}连接成功" << endi;
pDB = &m_ShmDB;
<%foreach table in tables%>
m_${table}.Init(pDB);
<%endforeach%>
<%foreach sequence in sequences%>
m_${sequence}.Init(pDB);
<%endforeach%>
return true;
}
//直连断开
bool DBUnInit()
{
#ifdef CTFC_${SYS}_H_SHM_DB
CShmActiveObjects * p;
p = m_ShmDB.GetCShmActiveObjects();
if (p->isConnected())p->Detach();
#endif
#ifdef CTFC_${SYS}_H_MARIA_DB
pDB->Close();
#endif
pDB = NULL;
return true;
}
//直连创建所有数据库对象
bool DBCreateAllDBObject()
{
//创建表
<%foreach table in tables%>
if(!m_${table}.CreateTable())return false;
<%endforeach%>
//创建序列
<%foreach sequence in sequences%>
if(!m_${sequence}.CreateSequence())return false;
<%endforeach%>
return true;
}
//直连显示所有数据库对象
bool DBShowAllDBObject()
{
//显示表
<%foreach table in tables%>
if(!m_${table}.Show())return false;
<%endforeach%>
//显示序列
thelog << "sequence:" << endl << "-------------------------" << endl;
<%foreach sequence in sequences%>
theLog<< "${sequence} " << m_${sequence}.GetSequenceValue() << endl;
<%endforeach%>
theLog << "-------------------------" << endi;
return true;
}
#endif
};
}
#endif
这就是一个代码模板编写的典型例子,用到了大量的循环处理和变量替换。看起来像asp?嗯,就是模仿asp啊。
三、如何创建模型
下一篇将详细解释这个模型(原则上,除了最终生成的的是这个脚本生成器要求的对象结构外模型和脚本生成器并没有更多关联)。
(这里是结束,但不是整个系列的结束)