Commit e57b843f authored by nicolas riesch's avatar nicolas riesch

fix SHOW COLL. Add SHOW LANGUAGE.

parent 8ccb977a
Pipeline #1295910 skipped
......@@ -51,6 +51,7 @@
- With RSQL, set @variable doesn't reset @@rowcount. MS SQL Server resets it.
- RSQL doesnt allow single and double quotes in delimited identifiers. MS SQL Server allows it.
......@@ -18,13 +18,12 @@ const (
OPTION_ANSI_NULL_DFLT_ON // option for parser: for CREATE TABLE, column without NULL/NOT NULL clause are NULL. This option is set by default.
OPTION_PARSEONLY // option for caller's use: only parse the batch. No execution.
OPTION_NOEXEC // option for caller's use: same as PARSEONLY.
OPTION_SHOWTREE // option for caller's use: show AST, after it has been parsed and decorated.
)
func Get_default_options() Options_t {
var (
options Options_t
)
var (
options Options_t
)
options |= OPTION_ANSI_NULL_DFLT_ON // options must be ORed
......
......@@ -39,7 +39,7 @@ func (parser *Parser) get_statement_SHOW_INFO() (*Token_stmt_SHOW_INFO, *rsql.Er
// parse SHOW COLLATIONS statement.
// This statement doesn't exist in MS SQL Server.
//
// SHOW {COLLATION|COLLATIONS}
// SHOW {COLL|COLLATION|COLLATIONS}
//
// Displays a list of all supported collations.
//
......@@ -58,7 +58,7 @@ func (parser *Parser) get_statement_SHOW_COLLATIONS() (*Token_stmt_SHOW_COLLATIO
// parse SHOW LANGUAGES statement.
// This statement doesn't exist in MS SQL Server.
//
// SHOW {LANGUAGE|LANGUAGES}
// SHOW {LANG|LANGUAGE|LANGUAGES}
//
// Displays a list of all supported languages.
//
......
......@@ -109,7 +109,7 @@ func (parser *Parser) get_statement_PRINT() (*Token_stmt_PRINT, *rsql.Error) {
return token_stmt_print, nil
}
// get_statement_SET_LEXER_OR_PARSER_OPTION parses "SET option" statements, e.g. SET PARSEONLY ON, SET PARSEONLY OFF, SET NOEXEC ON, SET SHOWTREE ON, SET QUOTED_IDENTIFIER ON, etc.
// get_statement_SET_LEXER_OR_PARSER_OPTION parses "SET option" statements, e.g. SET PARSEONLY ON, SET PARSEONLY OFF, SET NOEXEC ON, SET QUOTED_IDENTIFIER ON, etc.
//
// This instruction is a pragma for lexer or parser. It is not executed by the VM, no instruction is emitted.
//
......@@ -118,7 +118,6 @@ func (parser *Parser) get_statement_PRINT() (*Token_stmt_PRINT, *rsql.Error) {
// - SET ANSI_NULL_DFLT_ON ON/OFF for CREATE TABLE, column without NULL/NOT NULL clause are NULL.
// - SET PARSEONLY ON/OFF only parse the batch. No execution.
// - SET NOEXEC ON/OFF same as PARSEONLY
// - SET SHOWTREE ON/OFF show AST tree
//
func (parser *Parser) get_statement_SET_LEXER_OR_PARSER_OPTION(auxword lex.Auxword_t) (*Token_stmt_SET_LEXER_OR_PARSER_OPTION, *rsql.Error) {
var (
......@@ -146,9 +145,6 @@ func (parser *Parser) get_statement_SET_LEXER_OR_PARSER_OPTION(auxword lex.Auxwo
case lex.AUXWORD_NOEXEC: // pragma for caller's use only
option = OPTION_NOEXEC
case lex.AUXWORD_SHOWTREE: // pragma for caller's use only
option = OPTION_SHOWTREE
default:
panic("unexpected SET option")
}
......
......@@ -847,20 +847,20 @@ func (parser *Parser) get_statement() (sequence_first Tokener, sequence_last Tok
return nil, nil, rsql_err
}
switch {
case parser.Current_lexeme.Lex_type == lex.LEX_IDENTPART && (parser.Current_lexeme.Lex_word == string(lex.AUXWORD_I) || parser.Current_lexeme.Lex_word == string(lex.AUXWORD_INFO)):
switch subcommand := parser.Current_lexeme.Lex_word; {
case parser.Current_lexeme.Lex_type == lex.LEX_IDENTPART && (subcommand == string(lex.AUXWORD_I) || subcommand == string(lex.AUXWORD_INFO)):
statement_single, rsql_err = parser.get_statement_SHOW_INFO()
case parser.Current_lexeme.Lex_type == lex.LEX_IDENTPART && (parser.Current_lexeme.Lex_word == string(lex.AUXWORD_COLLATION) || parser.Current_lexeme.Lex_word == string(lex.AUXWORD_COLLATIONS)):
case parser.Current_lexeme.Lex_type == lex.LEX_IDENTPART && (subcommand == string(lex.AUXWORD_COLL) || subcommand == string(lex.AUXWORD_COLLATION) || subcommand == string(lex.AUXWORD_COLLATIONS)):
statement_single, rsql_err = parser.get_statement_SHOW_COLLATIONS()
case parser.Current_lexeme.Lex_type == lex.LEX_IDENTPART && (parser.Current_lexeme.Lex_word == string(lex.AUXWORD_LANGUAGE) || parser.Current_lexeme.Lex_word == string(lex.AUXWORD_LANGUAGES)):
case parser.Current_lexeme.Lex_type == lex.LEX_IDENTPART && (subcommand == string(lex.AUXWORD_LANG) || subcommand == string(lex.AUXWORD_LANGUAGE) || subcommand == string(lex.AUXWORD_LANGUAGES)):
statement_single, rsql_err = parser.get_statement_SHOW_LANGUAGES()
case parser.Current_lexeme.Lex_type == lex.LEX_IDENTPART && (parser.Current_lexeme.Lex_word == string(lex.AUXWORD_LOCK) || parser.Current_lexeme.Lex_word == string(lex.AUXWORD_LOCKS)):
case parser.Current_lexeme.Lex_type == lex.LEX_IDENTPART && (subcommand == string(lex.AUXWORD_LOCK) || subcommand == string(lex.AUXWORD_LOCKS)):
statement_single, rsql_err = parser.get_statement_SHOW_LOCKS()
case parser.Current_lexeme.Lex_type == lex.LEX_IDENTPART && (parser.Current_lexeme.Lex_word == string(lex.AUXWORD_WORKER) || parser.Current_lexeme.Lex_word == string(lex.AUXWORD_WORKERS)):
case parser.Current_lexeme.Lex_type == lex.LEX_IDENTPART && (subcommand == string(lex.AUXWORD_WORKER) || subcommand == string(lex.AUXWORD_WORKERS)):
statement_single, rsql_err = parser.get_statement_SHOW_WORKERS()
default:
......@@ -924,8 +924,7 @@ func (parser *Parser) get_statement() (sequence_first Tokener, sequence_last Tok
case lex.AUXWORD_QUOTED_IDENTIFIER, // pragma for lexer use only
lex.AUXWORD_ANSI_NULL_DFLT_ON, // pragma for parser use only
lex.AUXWORD_PARSEONLY, // pragma for caller's use only
lex.AUXWORD_NOEXEC, // pragma for caller's use only
lex.AUXWORD_SHOWTREE: // pragma for caller's use only
lex.AUXWORD_NOEXEC: // pragma for caller's use only
statement_single, rsql_err = parser.get_statement_SET_LEXER_OR_PARSER_OPTION(lex.Auxword_t(auxword)) // pragma. No instruction is output for the VM.
default:
......
......@@ -341,20 +341,20 @@ var WINDOWS_TO_COLLATION_MAP = map[string]string{
}
//=======================================================================
// init() creates collation list for SHOW COLLATIONS
// init() creates collation list for SHOW COLLATION
//=======================================================================
type Collinfo_t struct {
Name string
Aliases []string
Label string
type collinfo_t struct {
Name string
Aliases []string
Description string
}
type ByName []Collinfo_t
type byName []collinfo_t
func (a ByName) Len() int { return len(a) }
func (a ByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
func (a byName) Len() int { return len(a) }
func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool { return a[i].Description < a[j].Description }
var G_LIST_OF_RSQL_COLLATIONS_FOR_DISPLAY string
......@@ -365,7 +365,7 @@ func init() {
var (
err error
namer display.Namer
supported_collations []Collinfo_t
supported_collations []collinfo_t
tag language.Tag
aliases_map map[string][]string // for each collation short name, put all aliases
buff bytes.Buffer
......@@ -390,23 +390,23 @@ func init() {
namer = display.English.Tags()
supported_collations = make([]Collinfo_t, 0, len(G_COLLATION_MAP))
supported_collations = make([]collinfo_t, 0, len(G_COLLATION_MAP))
for name, internalname := range G_COLLATION_MAP {
if tag, err = language.Parse(internalname); err != nil { // we need the Tag to get a name to display
log.Fatalf("%s", err)
}
collinfo := Collinfo_t{Name: name, Aliases: aliases_map[name], Label: namer.Name(tag)}
collinfo := collinfo_t{Name: name, Aliases: aliases_map[name], Description: namer.Name(tag)}
supported_collations = append(supported_collations, collinfo)
}
sort.Sort(ByName(supported_collations)) // sort list
sort.Sort(byName(supported_collations)) // sort list
fmt.Fprintf(&buff, "%-25s %-14s %s\n", "Label", "Collation", "Aliases")
fmt.Fprintf(&buff, "%-25s %-14s %s\n", "-----", "---------", "-------")
fmt.Fprintf(&buff, "%-25s %-14s %s\n", "Description", "Collation", "Aliases")
fmt.Fprintf(&buff, "%-25s %-14s %s\n", "-----------", "---------", "-------")
for _, collinfo := range supported_collations { // write list
fmt.Fprintf(&buff, "%-25s %-14s %s\n", collinfo.Label, collinfo.Name, strings.Join(collinfo.Aliases, ", "))
fmt.Fprintf(&buff, "%-25s %-14s %s\n", collinfo.Description, collinfo.Name, strings.Join(collinfo.Aliases, ", "))
}
G_LIST_OF_RSQL_COLLATIONS_FOR_DISPLAY = buff.String() // put result in global variable
......
package lang
import (
"bytes"
"fmt"
"sort"
"strings"
"rsql"
......@@ -5359,3 +5362,67 @@ var LANGINFO_MAP = map[string]*Langinfo{
Lng_number_grouping: []int{3},
},
}
//=======================================================================
// init() creates language list for SHOW LANGUAGE
//=======================================================================
type lang_item_t struct {
Name string // fr-FR
Aliases []string // français, french
Description string // French (France)
}
type byName []lang_item_t
func (a byName) Len() int { return len(a) }
func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool { return a[i].Description < a[j].Description }
var G_LIST_OF_RSQL_LANGUAGES_FOR_DISPLAY string
// creates the global variable G_LIST_OF_RSQL_LANGUAGES_FOR_DISPLAY, containing the list of languages.
// This variable is used by SHOW LANGUAGES.
//
func init() {
var (
supported_languages []lang_item_t
aliases_map map[string][]string // for each language short name, put all aliases
buff bytes.Buffer
)
// create aliases map
aliases_map = make(map[string][]string, len(LANGUAGE_TO_TAG_MAP)) // e.g. "fr-FR" --> "français", "french"
for alias, name := range LANGUAGE_TO_TAG_MAP {
aliases_map[name] = append(aliases_map[name], alias)
}
for name, aliases := range aliases_map { // for each collation, sort list of aliases
if len(aliases) > 1 {
sort.Strings(aliases)
aliases_map[name] = aliases
}
}
// create rsql languages list
supported_languages = make([]lang_item_t, 0, len(LANGINFO_MAP))
for key, langinfo := range LANGINFO_MAP {
item := lang_item_t{Name: langinfo.Lng_locale_name, Aliases: aliases_map[key], Description: langinfo.Lng_locale_description}
supported_languages = append(supported_languages, item)
}
sort.Sort(byName(supported_languages)) // sort list
fmt.Fprintf(&buff, "%-52s %-16s %s\n", "Description", "Language", "Aliases")
fmt.Fprintf(&buff, "%-52s %-16s %s\n", "-----------", "--------", "-------")
for _, item := range supported_languages { // write list
fmt.Fprintf(&buff, "%-52s %-16s %s\n", item.Description, item.Name, strings.Join(item.Aliases, ", "))
}
G_LIST_OF_RSQL_LANGUAGES_FOR_DISPLAY = buff.String() // put result in global variable
}
......@@ -4,7 +4,6 @@ type Auxword_t string
// miscellaneous auxilliary words, which are not keywords but LEX_IDENTPART.
// They are used in SQL batch e.g. as option names, or after SET keyword like in SET LANGUAGE.
// SET SHOWTREE is a RSQL Server statement, not a MS SQL Server statement.
//
const (
AUXWORD_DATEFIRST Auxword_t = "datefirst"
......@@ -50,7 +49,6 @@ const (
AUXWORD_QUOTED_IDENTIFIER Auxword_t = "quoted_identifier"
AUXWORD_PARSEONLY Auxword_t = "parseonly"
AUXWORD_NOEXEC Auxword_t = "noexec"
AUXWORD_SHOWTREE Auxword_t = "showtree"
AUXWORD_ANSI_NULL_DFLT_ON Auxword_t = "ansi_null_dflt_on"
AUXWORD_ANSI_NULLS Auxword_t = "ansi_nulls"
AUXWORD_MYCODE Auxword_t = "mycode"
......@@ -101,8 +99,10 @@ const (
AUXWORD_INFO Auxword_t = "info"
AUXWORD_I Auxword_t = "i"
AUXWORD_DDL_ONLY Auxword_t = "ddl_only"
AUXWORD_COLL Auxword_t = "coll"
AUXWORD_COLLATION Auxword_t = "collation"
AUXWORD_COLLATIONS Auxword_t = "collations"
AUXWORD_LANG Auxword_t = "lang"
AUXWORD_LANGUAGE Auxword_t = "language"
AUXWORD_LANGUAGES Auxword_t = "languages"
AUXWORD_LOCK Auxword_t = "lock"
......
......@@ -14,15 +14,22 @@ use trashdb
-- An attempt to create a table with a reserved keyword as a name
-- should fail.
use mydb
print '------' + db_name()
CREATE TABLE "select" ("identity" INT IDENTITY NOT NULL, "order" INT NOT NULL);
show coll
exit
SET LANGUAGE fr_FR;
SET LANGUAGE [fr_FR];
SET LANGUAGE 'fr_FR';
SET LANGUAGE [fr-FR];
SET LANGUAGE 'fr-FR';
SET LANGUAGE French;
SET LANGUAGE [French];
SET LANGUAGE 'French';
show languages
go
use trashdb
print '------' + db_name()
CREATE TABLE "select" ("identity" INT IDENTITY NOT NULL, "order" INT NOT NULL);
quit
......
......@@ -410,7 +410,7 @@ func handle_connection(conn net.Conn, worker *cache.Worker) {
// print AST if requested
if msg_auth.opt_showtree || decor.Option(ast.OPTION_SHOWTREE) == true {
if msg_auth.opt_showtree {
if rsql_err = ast.Debug_print_AST(context, decor.Batch_ast_anchor); rsql_err != nil {
goto RSQL_ERROR_OCCURRED
}
......@@ -430,6 +430,10 @@ func handle_connection(conn net.Conn, worker *cache.Worker) {
// VM executes instructions
if decor.Options&(ast.OPTION_PARSEONLY|ast.OPTION_NOEXEC) != 0 {
goto LABEL_SKIP_EXEC
}
context.Keepalive_start(time.Duration(param_keepalive_interval) * time.Millisecond)
retval, rsql_err = vm.Execute_basicblocks_all(context, decor.Basicblock_first) // in context, wcache can have been recreated by COMMIT or ROLLBACK statement.
wcache = context.Ctx_wcache.(*cache.Wcache)
......@@ -439,8 +443,9 @@ func handle_connection(conn net.Conn, worker *cache.Worker) {
goto RSQL_ERROR_OCCURRED
}
LABEL_SKIP_EXEC:
current_database = decor.VARIABLES.Get_current_db_name() // get current database
current_options = decor.Options // get current options
current_options = decor.Options // get current options
// rollback if a transaction is pending
......
......@@ -21,7 +21,7 @@ func USE(context *rsql.Context, database_name string, vars_OUT []rsql.IDataslot)
wcache.Wpc_last_rowcount = 0
if database_dbid, schema_name, schema_schid, user_name, user_palid, rsql_err = dict.MASTER.Use_sysdatabase(context.Ctx_login_id, context.Ctx_login_name_for_info, database_name); rsql_err != nil {
return rsql_err
return rsql_err // error aborts the session
}
// assign values to _@current_db_name, etc
......
......@@ -7,6 +7,7 @@ import (
"rsql"
"rsql/data"
"rsql/dict"
"rsql/lang"
"rsql/lk"
)
......@@ -25,7 +26,7 @@ func SHOW_LANGUAGES(context *rsql.Context) *rsql.Error {
// print
if rsql_err := context.Send_MESSAGE("blabla"); rsql_err != nil {
if rsql_err := context.Send_MESSAGE(lang.G_LIST_OF_RSQL_LANGUAGES_FOR_DISPLAY); rsql_err != nil {
return rsql_err
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment