gosora/query_gen/lib/mysql.go
Azareal 22650aad27 Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.

Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.

Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 11:20:28 +01:00

864 lines
24 KiB
Go

/* WIP Under Construction */
package qgen
//import "fmt"
import "strings"
import "strconv"
import "errors"
func init() {
DB_Registry = append(DB_Registry,
&Mysql_Adapter{Name: "mysql", Buffer: make(map[string]DB_Stmt)},
)
}
type Mysql_Adapter struct {
Name string // ? - Do we really need this? Can't we hard-code this?
Buffer map[string]DB_Stmt
BufferOrder []string // Map iteration order is random, so we need this to track the order, so we don't get huge diffs every commit
}
// GetName gives you the name of the database adapter. In this case, it's mysql
func (adapter *Mysql_Adapter) GetName() string {
return adapter.Name
}
func (adapter *Mysql_Adapter) GetStmt(name string) DB_Stmt {
return adapter.Buffer[name]
}
func (adapter *Mysql_Adapter) GetStmts() map[string]DB_Stmt {
return adapter.Buffer
}
func (adapter *Mysql_Adapter) CreateTable(name string, table string, charset string, collation string, columns []DB_Table_Column, keys []DB_Table_Key) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table == "" {
return "", errors.New("You need a name for this table")
}
if len(columns) == 0 {
return "", errors.New("You can't have a table with no columns")
}
var querystr = "CREATE TABLE `" + table + "` ("
for _, column := range columns {
// Make it easier to support Cassandra in the future
if column.Type == "createdAt" {
column.Type = "datetime"
}
var size string
if column.Size > 0 {
size = "(" + strconv.Itoa(column.Size) + ")"
}
var end string
// TODO: Exclude the other variants of text like mediumtext and longtext too
if column.Default != "" && column.Type != "text" {
end = " DEFAULT "
if adapter.stringyType(column.Type) && column.Default != "''" {
end += "'" + column.Default + "'"
} else {
end += column.Default
}
}
if column.Null {
end += " null"
} else {
end += " not null"
}
if column.Auto_Increment {
end += " AUTO_INCREMENT"
}
querystr += "\n\t`" + column.Name + "` " + column.Type + size + end + ","
}
if len(keys) > 0 {
for _, key := range keys {
querystr += "\n\t" + key.Type
if key.Type != "unique" {
querystr += " key"
}
querystr += "("
for _, column := range strings.Split(key.Columns, ",") {
querystr += "`" + column + "`,"
}
querystr = querystr[0:len(querystr)-1] + "),"
}
}
querystr = querystr[0:len(querystr)-1] + "\n)"
if charset != "" {
querystr += " CHARSET=" + charset
}
if collation != "" {
querystr += " COLLATE " + collation
}
adapter.pushStatement(name, "create-table", querystr+";")
return querystr + ";", nil
}
func (adapter *Mysql_Adapter) SimpleInsert(name string, table string, columns string, fields string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table == "" {
return "", errors.New("You need a name for this table")
}
if len(columns) == 0 {
return "", errors.New("No columns found for SimpleInsert")
}
if len(fields) == 0 {
return "", errors.New("No input data found for SimpleInsert")
}
var querystr = "INSERT INTO `" + table + "`("
// Escape the column names, just in case we've used a reserved keyword
for _, column := range processColumns(columns) {
if column.Type == "function" {
querystr += column.Left + ","
} else {
querystr += "`" + column.Left + "`,"
}
}
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
querystr += ") VALUES ("
for _, field := range processFields(fields) {
querystr += field.Name + ","
}
querystr = querystr[0 : len(querystr)-1]
adapter.pushStatement(name, "insert", querystr+")")
return querystr + ")", nil
}
func (adapter *Mysql_Adapter) SimpleReplace(name string, table string, columns string, fields string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table == "" {
return "", errors.New("You need a name for this table")
}
if len(columns) == 0 {
return "", errors.New("No columns found for SimpleInsert")
}
if len(fields) == 0 {
return "", errors.New("No input data found for SimpleInsert")
}
var querystr = "REPLACE INTO `" + table + "`("
// Escape the column names, just in case we've used a reserved keyword
for _, column := range processColumns(columns) {
if column.Type == "function" {
querystr += column.Left + ","
} else {
querystr += "`" + column.Left + "`,"
}
}
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
querystr += ") VALUES ("
for _, field := range processFields(fields) {
querystr += field.Name + ","
}
querystr = querystr[0 : len(querystr)-1]
adapter.pushStatement(name, "replace", querystr+")")
return querystr + ")", nil
}
func (adapter *Mysql_Adapter) SimpleUpdate(name string, table string, set string, where string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table == "" {
return "", errors.New("You need a name for this table")
}
if set == "" {
return "", errors.New("You need to set data in this update statement")
}
var querystr = "UPDATE `" + table + "` SET "
for _, item := range processSet(set) {
querystr += "`" + item.Column + "` ="
for _, token := range item.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
querystr += " `" + token.Contents + "`"
case "string":
querystr += " '" + token.Contents + "'"
}
}
querystr += ","
}
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
// Add support for BETWEEN x.x
if len(where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
querystr += " `" + token.Contents + "`"
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
}
adapter.pushStatement(name, "update", querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) SimpleDelete(name string, table string, where string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table == "" {
return "", errors.New("You need a name for this table")
}
if where == "" {
return "", errors.New("You need to specify what data you want to delete")
}
var querystr = "DELETE FROM `" + table + "` WHERE"
// Add support for BETWEEN x.x
for _, loc := range processWhere(where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
querystr += " `" + token.Contents + "`"
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = strings.TrimSpace(querystr[0 : len(querystr)-4])
adapter.pushStatement(name, "delete", querystr)
return querystr, nil
}
// We don't want to accidentally wipe tables, so we'll have a seperate method for purging tables instead
func (adapter *Mysql_Adapter) Purge(name string, table string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table == "" {
return "", errors.New("You need a name for this table")
}
adapter.pushStatement(name, "purge", "DELETE FROM `"+table+"`")
return "DELETE FROM `" + table + "`", nil
}
func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table == "" {
return "", errors.New("You need a name for this table")
}
if len(columns) == 0 {
return "", errors.New("No columns found for SimpleSelect")
}
// Slice up the user friendly strings into something easier to process
var colslice = strings.Split(strings.TrimSpace(columns), ",")
var querystr = "SELECT "
// Escape the column names, just in case we've used a reserved keyword
for _, column := range colslice {
querystr += "`" + strings.TrimSpace(column) + "`,"
}
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + table + "`"
// Add support for BETWEEN x.x
if len(where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
querystr += " `" + token.Contents + "`"
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
}
if len(orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(orderby) {
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
}
querystr = querystr[0 : len(querystr)-1]
}
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "select", querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table1 == "" {
return "", errors.New("You need a name for the left table")
}
if table2 == "" {
return "", errors.New("You need a name for the right table")
}
if len(columns) == 0 {
return "", errors.New("No columns found for SimpleLeftJoin")
}
if len(joiners) == 0 {
return "", errors.New("No joiners found for SimpleLeftJoin")
}
var querystr = "SELECT "
for _, column := range processColumns(columns) {
var source, alias string
// Escape the column names, just in case we've used a reserved keyword
if column.Table != "" {
source = "`" + column.Table + "`.`" + column.Left + "`"
} else if column.Type == "function" {
source = column.Left
} else {
source = "`" + column.Left + "`"
}
if column.Alias != "" {
alias = " AS `" + column.Alias + "`"
}
querystr += source + alias + ","
}
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + table1 + "` LEFT JOIN `" + table2 + "` ON "
for _, joiner := range processJoiner(joiners) {
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
}
// Remove the trailing AND
querystr = querystr[0 : len(querystr)-4]
// Add support for BETWEEN x.x
if len(where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
halves := strings.Split(token.Contents, ".")
if len(halves) == 2 {
querystr += " `" + halves[0] + "`.`" + halves[1] + "`"
} else {
querystr += " `" + token.Contents + "`"
}
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
}
if len(orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(orderby) {
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
}
querystr = querystr[0 : len(querystr)-1]
}
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "select", querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table1 == "" {
return "", errors.New("You need a name for the left table")
}
if table2 == "" {
return "", errors.New("You need a name for the right table")
}
if len(columns) == 0 {
return "", errors.New("No columns found for SimpleInnerJoin")
}
if len(joiners) == 0 {
return "", errors.New("No joiners found for SimpleInnerJoin")
}
var querystr = "SELECT "
for _, column := range processColumns(columns) {
var source, alias string
// Escape the column names, just in case we've used a reserved keyword
if column.Table != "" {
source = "`" + column.Table + "`.`" + column.Left + "`"
} else if column.Type == "function" {
source = column.Left
} else {
source = "`" + column.Left + "`"
}
if column.Alias != "" {
alias = " AS `" + column.Alias + "`"
}
querystr += source + alias + ","
}
// Remove the trailing comma
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + table1 + "` INNER JOIN `" + table2 + "` ON "
for _, joiner := range processJoiner(joiners) {
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
}
// Remove the trailing AND
querystr = querystr[0 : len(querystr)-4]
// Add support for BETWEEN x.x
if len(where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
halves := strings.Split(token.Contents, ".")
if len(halves) == 2 {
querystr += " `" + halves[0] + "`.`" + halves[1] + "`"
} else {
querystr += " `" + token.Contents + "`"
}
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
}
if len(orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(orderby) {
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
}
querystr = querystr[0 : len(querystr)-1]
}
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "select", querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel DB_Select) (string, error) {
/* Insert Portion */
var querystr = "INSERT INTO `" + ins.Table + "`("
// Escape the column names, just in case we've used a reserved keyword
for _, column := range processColumns(ins.Columns) {
if column.Type == "function" {
querystr += column.Left + ","
} else {
querystr += "`" + column.Left + "`,"
}
}
querystr = querystr[0:len(querystr)-1] + ") SELECT"
/* Select Portion */
for _, column := range processColumns(sel.Columns) {
var source, alias string
// Escape the column names, just in case we've used a reserved keyword
if column.Type == "function" || column.Type == "substitute" {
source = column.Left
} else {
source = "`" + column.Left + "`"
}
if column.Alias != "" {
alias = " AS `" + column.Alias + "`"
}
querystr += " " + source + alias + ","
}
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + sel.Table + "`"
// Add support for BETWEEN x.x
if len(sel.Where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(sel.Where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
querystr += " `" + token.Contents + "`"
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
}
if len(sel.Orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(sel.Orderby) {
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
}
querystr = querystr[0 : len(querystr)-1]
}
if sel.Limit != "" {
querystr += " LIMIT " + sel.Limit
}
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "insert", querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) SimpleInsertLeftJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
/* Insert Portion */
var querystr = "INSERT INTO `" + ins.Table + "`("
// Escape the column names, just in case we've used a reserved keyword
for _, column := range processColumns(ins.Columns) {
if column.Type == "function" {
querystr += column.Left + ","
} else {
querystr += "`" + column.Left + "`,"
}
}
querystr = querystr[0:len(querystr)-1] + ") SELECT"
/* Select Portion */
for _, column := range processColumns(sel.Columns) {
var source, alias string
// Escape the column names, just in case we've used a reserved keyword
if column.Table != "" {
source = "`" + column.Table + "`.`" + column.Left + "`"
} else if column.Type == "function" {
source = column.Left
} else {
source = "`" + column.Left + "`"
}
if column.Alias != "" {
alias = " AS `" + column.Alias + "`"
}
querystr += " " + source + alias + ","
}
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + sel.Table1 + "` LEFT JOIN `" + sel.Table2 + "` ON "
for _, joiner := range processJoiner(sel.Joiners) {
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
}
querystr = querystr[0 : len(querystr)-4]
// Add support for BETWEEN x.x
if len(sel.Where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(sel.Where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
halves := strings.Split(token.Contents, ".")
if len(halves) == 2 {
querystr += " `" + halves[0] + "`.`" + halves[1] + "`"
} else {
querystr += " `" + token.Contents + "`"
}
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
}
if len(sel.Orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(sel.Orderby) {
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
}
querystr = querystr[0 : len(querystr)-1]
}
if sel.Limit != "" {
querystr += " LIMIT " + sel.Limit
}
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "insert", querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) SimpleInsertInnerJoin(name string, ins DB_Insert, sel DB_Join) (string, error) {
/* Insert Portion */
var querystr = "INSERT INTO `" + ins.Table + "`("
// Escape the column names, just in case we've used a reserved keyword
for _, column := range processColumns(ins.Columns) {
if column.Type == "function" {
querystr += column.Left + ","
} else {
querystr += "`" + column.Left + "`,"
}
}
querystr = querystr[0:len(querystr)-1] + ") SELECT"
/* Select Portion */
for _, column := range processColumns(sel.Columns) {
var source, alias string
// Escape the column names, just in case we've used a reserved keyword
if column.Table != "" {
source = "`" + column.Table + "`.`" + column.Left + "`"
} else if column.Type == "function" {
source = column.Left
} else {
source = "`" + column.Left + "`"
}
if column.Alias != "" {
alias = " AS `" + column.Alias + "`"
}
querystr += " " + source + alias + ","
}
querystr = querystr[0 : len(querystr)-1]
querystr += " FROM `" + sel.Table1 + "` INNER JOIN `" + sel.Table2 + "` ON "
for _, joiner := range processJoiner(sel.Joiners) {
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
}
querystr = querystr[0 : len(querystr)-4]
// Add support for BETWEEN x.x
if len(sel.Where) != 0 {
querystr += " WHERE"
for _, loc := range processWhere(sel.Where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
halves := strings.Split(token.Contents, ".")
if len(halves) == 2 {
querystr += " `" + halves[0] + "`.`" + halves[1] + "`"
} else {
querystr += " `" + token.Contents + "`"
}
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
}
if len(sel.Orderby) != 0 {
querystr += " ORDER BY "
for _, column := range processOrderby(sel.Orderby) {
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
}
querystr = querystr[0 : len(querystr)-1]
}
if sel.Limit != "" {
querystr += " LIMIT " + sel.Limit
}
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "insert", querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where string, limit string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
if table == "" {
return "", errors.New("You need a name for this table")
}
var querystr = "SELECT COUNT(*) AS `count` FROM `" + table + "`"
// Add support for BETWEEN x.x
if len(where) != 0 {
querystr += " WHERE"
//fmt.Println("SimpleCount:",name)
//fmt.Println("where:",where)
//fmt.Println("_process_where:",_process_where(where))
for _, loc := range processWhere(where) {
for _, token := range loc.Expr {
switch token.Type {
case "function", "operator", "number", "substitute":
querystr += " " + token.Contents
case "column":
querystr += " `" + token.Contents + "`"
case "string":
querystr += " '" + token.Contents + "'"
default:
panic("This token doesn't exist o_o")
}
}
querystr += " AND"
}
querystr = querystr[0 : len(querystr)-4]
}
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr)
adapter.pushStatement(name, "select", querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) Write() error {
var stmts, body string
for _, name := range adapter.BufferOrder {
stmt := adapter.Buffer[name]
// TODO: Add support for create-table? Table creation might be a little complex for Go to do outside a SQL file :(
if stmt.Type != "create-table" {
stmts += "var " + name + "Stmt *sql.Stmt\n"
body += `
log.Print("Preparing ` + name + ` statement.")
` + name + `Stmt, err = db.Prepare("` + stmt.Contents + `")
if err != nil {
return err
}
`
}
}
out := `// +build !pgsql !sqlite !mssql
/* This file was generated by Gosora's Query Generator. Please try to avoid modifying this file, as it might change at any time. */
package main
import "log"
import "database/sql"
// nolint
` + stmts + `
// nolint
func _gen_mysql() (err error) {
if dev.DebugMode {
log.Print("Building the generated statements")
}
` + body + `
return nil
}
`
return writeFile("./gen_mysql.go", out)
}
// Internal methods, not exposed in the interface
func (adapter *Mysql_Adapter) pushStatement(name string, stype string, querystr string) {
adapter.Buffer[name] = DB_Stmt{querystr, stype}
adapter.BufferOrder = append(adapter.BufferOrder, name)
}
func (adapter *Mysql_Adapter) stringyType(ctype string) bool {
ctype = strings.ToLower(ctype)
return ctype == "varchar" || ctype == "tinytext" || ctype == "text" || ctype == "mediumtext" || ctype == "longtext" || ctype == "char" || ctype == "datetime" || ctype == "timestamp" || ctype == "time" || ctype == "date"
}