Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gosqlite
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
gosqlite
Commits
4d9000a7
Commit
4d9000a7
authored
Apr 12, 2015
by
gwenn
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Ensures the column index is valid.
parent
014b1ec7
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
253 additions
and
127 deletions
+253
-127
csv.go
csv.go
+3
-2
csv_test.go
csv_test.go
+11
-6
driver.go
driver.go
+3
-1
meta.go
meta.go
+23
-8
meta_extra.go
meta_extra.go
+15
-6
meta_extra_test.go
meta_extra_test.go
+30
-15
meta_test.go
meta_test.go
+30
-10
stmt.go
stmt.go
+116
-69
stmt_test.go
stmt_test.go
+22
-10
No files found.
csv.go
View file @
4d9000a7
...
...
@@ -331,8 +331,9 @@ func (s *Stmt) ExportToCSV(nullvalue string, headers bool, w *yacr.Writer) error
}
s
.
Select
(
func
(
s
*
Stmt
)
error
{
for
i
:=
0
;
i
<
s
.
ColumnCount
();
i
++
{
rb
,
null
:=
s
.
ScanRawBytes
(
i
)
if
null
{
if
rb
,
null
,
err
:=
s
.
ScanRawBytes
(
i
);
err
!=
nil
{
return
err
}
else
if
null
{
w
.
Write
([]
byte
(
nullvalue
))
}
else
{
w
.
Write
(
rb
)
...
...
csv_test.go
View file @
4d9000a7
...
...
@@ -206,17 +206,22 @@ func TestImportAffinity(t *testing.T) {
err
:=
db
.
ImportCSV
(
r
,
ic
,
""
,
"test"
)
checkNoError
(
t
,
err
,
"error while importing CSV file: %s"
)
err
=
db
.
Select
(
"SELECT typeof(t), typeof(i), typeof(r), typeof(b), typeof(n) from test"
,
func
(
s
*
Stmt
)
error
{
tot
,
_
:=
s
.
ScanText
(
0
)
tot
,
_
,
err
:=
s
.
ScanText
(
0
)
checkNoError
(
t
,
err
,
"error while scanning: %s"
)
assert
.
Equal
(
t
,
"text"
,
tot
)
toi
,
_
:=
s
.
ScanText
(
1
)
toi
,
_
,
err
:=
s
.
ScanText
(
1
)
checkNoError
(
t
,
err
,
"error while scanning: %s"
)
assert
.
Equal
(
t
,
"integer"
,
toi
)
tor
,
_
:=
s
.
ScanText
(
2
)
tor
,
_
,
err
:=
s
.
ScanText
(
2
)
checkNoError
(
t
,
err
,
"error while scanning: %s"
)
assert
.
Equal
(
t
,
"real"
,
tor
)
tob
,
_
:=
s
.
ScanText
(
3
)
tob
,
_
,
err
:=
s
.
ScanText
(
3
)
checkNoError
(
t
,
err
,
"error while scanning: %s"
)
assert
.
Equal
(
t
,
"text"
,
tob
)
ton
,
_
:=
s
.
ScanText
(
4
)
ton
,
_
,
err
:=
s
.
ScanText
(
4
)
checkNoError
(
t
,
err
,
"error while scanning: %s"
)
assert
.
Equal
(
t
,
"integer"
,
ton
)
return
nil
return
err
})
checkNoError
(
t
,
err
,
"error while selecting: %s"
)
}
...
...
driver.go
View file @
4d9000a7
...
...
@@ -229,7 +229,9 @@ func (r *rowsImpl) Next(dest []driver.Value) error {
return
io
.
EOF
}
for
i
:=
range
dest
{
dest
[
i
],
_
=
r
.
s
.
s
.
ScanValue
(
i
,
true
)
if
dest
[
i
],
_
,
err
=
r
.
s
.
s
.
ScanValue
(
i
,
true
);
err
!=
nil
{
return
err
}
/*if !driver.IsScanValue(dest[i]) {
panic("Invalid type returned by ScanValue")
}*/
...
...
meta.go
View file @
4d9000a7
...
...
@@ -56,8 +56,11 @@ func (c *Conn) Tables(dbName string) ([]string, error) {
defer
s
.
finalize
()
var
tables
=
make
([]
string
,
0
,
20
)
err
=
s
.
Select
(
func
(
s
*
Stmt
)
(
err
error
)
{
name
,
_
:=
s
.
ScanText
(
0
)
tables
=
append
(
tables
,
name
)
if
name
,
_
,
err
:=
s
.
ScanText
(
0
);
err
!=
nil
{
return
err
}
else
{
tables
=
append
(
tables
,
name
)
}
return
})
if
err
!=
nil
{
...
...
@@ -84,8 +87,11 @@ func (c *Conn) Views(dbName string) ([]string, error) {
defer
s
.
finalize
()
var
views
=
make
([]
string
,
0
,
20
)
err
=
s
.
Select
(
func
(
s
*
Stmt
)
(
err
error
)
{
name
,
_
:=
s
.
ScanText
(
0
)
views
=
append
(
views
,
name
)
if
name
,
_
,
err
:=
s
.
ScanText
(
0
);
err
!=
nil
{
return
err
}
else
{
views
=
append
(
views
,
name
)
}
return
})
if
err
!=
nil
{
...
...
@@ -172,8 +178,11 @@ func (c *Conn) Columns(dbName, table string) ([]Column, error) {
// If the result column is an expression or subquery, then an empty string is returned.
// The left-most column is column 0.
// (See http://www.sqlite.org/c3ref/column_decltype.html)
func
(
s
*
Stmt
)
ColumnDeclaredType
(
index
int
)
string
{
return
C
.
GoString
(
C
.
sqlite3_column_decltype
(
s
.
stmt
,
C
.
int
(
index
)))
func
(
s
*
Stmt
)
ColumnDeclaredType
(
index
int
)
(
string
,
error
)
{
if
index
<
0
||
index
>=
s
.
ColumnCount
()
{
return
""
,
s
.
specificError
(
"column index %d out of range [0,%d[."
,
index
,
s
.
ColumnCount
())
}
return
C
.
GoString
(
C
.
sqlite3_column_decltype
(
s
.
stmt
,
C
.
int
(
index
))),
nil
}
// Affinity enumerates SQLite column type affinity
...
...
@@ -192,7 +201,13 @@ const (
// If the result column is an expression or subquery, then None is returned.
// The left-most column is column 0.
// (See http://sqlite.org/datatype3.html)
func
(
s
*
Stmt
)
ColumnTypeAffinity
(
index
int
)
Affinity
{
func
(
s
*
Stmt
)
ColumnTypeAffinity
(
index
int
)
(
Affinity
,
error
)
{
if
index
<
0
||
index
>=
s
.
ColumnCount
()
{
return
None
,
s
.
specificError
(
"column index %d out of range [0,%d[."
,
index
,
s
.
ColumnCount
())
}
return
s
.
columnTypeAffinity
(
index
),
nil
}
func
(
s
*
Stmt
)
columnTypeAffinity
(
index
int
)
Affinity
{
if
s
.
affinities
==
nil
{
count
:=
s
.
ColumnCount
()
s
.
affinities
=
make
([]
Affinity
,
count
)
...
...
@@ -201,7 +216,7 @@ func (s *Stmt) ColumnTypeAffinity(index int) Affinity {
return
affinity
}
}
declType
:=
s
.
ColumnDeclaredType
(
index
)
declType
,
_
:=
s
.
ColumnDeclaredType
(
index
)
affinity
:=
typeAffinity
(
declType
)
s
.
affinities
[
index
]
=
affinity
return
affinity
...
...
meta_extra.go
View file @
4d9000a7
...
...
@@ -46,22 +46,31 @@ func (c *Conn) Column(dbName, tableName, columnName string) (*Column, error) {
// that is the origin of a particular result column in SELECT statement.
// The left-most column is column 0.
// (See http://www.sqlite.org/c3ref/column_database_name.html)
func
(
s
*
Stmt
)
ColumnDatabaseName
(
index
int
)
string
{
return
C
.
GoString
(
C
.
sqlite3_column_database_name
(
s
.
stmt
,
C
.
int
(
index
)))
func
(
s
*
Stmt
)
ColumnDatabaseName
(
index
int
)
(
string
,
error
)
{
if
index
<
0
||
index
>=
s
.
ColumnCount
()
{
return
""
,
s
.
specificError
(
"column index %d out of range [0,%d[."
,
index
,
s
.
ColumnCount
())
}
return
C
.
GoString
(
C
.
sqlite3_column_database_name
(
s
.
stmt
,
C
.
int
(
index
))),
nil
}
// ColumnTableName returns the original un-aliased table name
// that is the origin of a particular result column in SELECT statement.
// The left-most column is column 0.
// (See http://www.sqlite.org/c3ref/column_database_name.html)
func
(
s
*
Stmt
)
ColumnTableName
(
index
int
)
string
{
return
C
.
GoString
(
C
.
sqlite3_column_table_name
(
s
.
stmt
,
C
.
int
(
index
)))
func
(
s
*
Stmt
)
ColumnTableName
(
index
int
)
(
string
,
error
)
{
if
index
<
0
||
index
>=
s
.
ColumnCount
()
{
return
""
,
s
.
specificError
(
"column index %d out of range [0,%d[."
,
index
,
s
.
ColumnCount
())
}
return
C
.
GoString
(
C
.
sqlite3_column_table_name
(
s
.
stmt
,
C
.
int
(
index
))),
nil
}
// ColumnOriginName returns the original un-aliased table column name
// that is the origin of a particular result column in SELECT statement.
// The left-most column is column 0.
// (See http://www.sqlite.org/c3ref/column_database_name.html)
func
(
s
*
Stmt
)
ColumnOriginName
(
index
int
)
string
{
return
C
.
GoString
(
C
.
sqlite3_column_origin_name
(
s
.
stmt
,
C
.
int
(
index
)))
func
(
s
*
Stmt
)
ColumnOriginName
(
index
int
)
(
string
,
error
)
{
if
index
<
0
||
index
>=
s
.
ColumnCount
()
{
return
""
,
s
.
specificError
(
"column index %d out of range [0,%d[."
,
index
,
s
.
ColumnCount
())
}
return
C
.
GoString
(
C
.
sqlite3_column_origin_name
(
s
.
stmt
,
C
.
int
(
index
))),
nil
}
meta_extra_test.go
View file @
4d9000a7
...
...
@@ -40,15 +40,20 @@ func TestColumnMetadata(t *testing.T) {
check
(
err
)
defer
checkFinalize
(
s
,
t
)
databaseName
:=
s
.
ColumnDatabaseName
(
0
)
databaseName
,
err
:=
s
.
ColumnDatabaseName
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
"main"
,
databaseName
,
"database name"
)
tableName
:=
s
.
ColumnTableName
(
0
)
tableName
,
err
:=
s
.
ColumnTableName
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
"sqlite_master"
,
tableName
,
"table name"
)
originName
:=
s
.
ColumnOriginName
(
0
)
originName
,
err
:=
s
.
ColumnOriginName
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
"name"
,
originName
,
"origin name"
)
declType
:=
s
.
ColumnDeclaredType
(
0
)
declType
,
err
:=
s
.
ColumnDeclaredType
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
"text"
,
declType
,
"declared type"
)
affinity
:=
s
.
ColumnTypeAffinity
(
0
)
affinity
,
err
:=
s
.
ColumnTypeAffinity
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
Textual
,
affinity
,
"affinity"
)
}
...
...
@@ -63,15 +68,20 @@ func TestColumnMetadataOnView(t *testing.T) {
check
(
err
)
defer
checkFinalize
(
s
,
t
)
databaseName
:=
s
.
ColumnDatabaseName
(
0
)
databaseName
,
err
:=
s
.
ColumnDatabaseName
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
"main"
,
databaseName
,
"database name"
)
tableName
:=
s
.
ColumnTableName
(
0
)
tableName
,
err
:=
s
.
ColumnTableName
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
"test"
,
tableName
,
"table name"
)
originName
:=
s
.
ColumnOriginName
(
0
)
originName
,
err
:=
s
.
ColumnOriginName
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
"a_string"
,
originName
,
"origin name"
)
declType
:=
s
.
ColumnDeclaredType
(
0
)
declType
,
err
:=
s
.
ColumnDeclaredType
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
"TEXT"
,
declType
,
"declared type"
)
affinity
:=
s
.
ColumnTypeAffinity
(
0
)
affinity
,
err
:=
s
.
ColumnTypeAffinity
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
Textual
,
affinity
,
"affinity"
)
}
...
...
@@ -85,14 +95,19 @@ func TestColumnMetadataOnExpr(t *testing.T) {
check
(
err
)
defer
checkFinalize
(
s
,
t
)
databaseName
:=
s
.
ColumnDatabaseName
(
0
)
databaseName
,
err
:=
s
.
ColumnDatabaseName
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
""
,
databaseName
,
"database name"
)
tableName
:=
s
.
ColumnTableName
(
0
)
tableName
,
err
:=
s
.
ColumnTableName
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
""
,
tableName
,
"table name"
)
originName
:=
s
.
ColumnOriginName
(
0
)
originName
,
err
:=
s
.
ColumnOriginName
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
""
,
originName
,
"origin name"
)
declType
:=
s
.
ColumnDeclaredType
(
0
)
declType
,
err
:=
s
.
ColumnDeclaredType
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
""
,
declType
,
"declared type"
)
affinity
:=
s
.
ColumnTypeAffinity
(
0
)
affinity
,
err
:=
s
.
ColumnTypeAffinity
(
0
)
check
(
err
)
assert
.
Equal
(
t
,
None
,
affinity
,
"affinity"
)
}
meta_test.go
View file @
4d9000a7
...
...
@@ -198,12 +198,24 @@ func TestColumnTypeAffinity(t *testing.T) {
checkNoError
(
t
,
err
,
"%s"
)
defer
checkFinalize
(
s
,
t
)
assert
.
Equal
(
t
,
Integral
,
s
.
ColumnTypeAffinity
(
0
),
"affinity"
)
assert
.
Equal
(
t
,
Real
,
s
.
ColumnTypeAffinity
(
1
),
"affinity"
)
assert
.
Equal
(
t
,
Numerical
,
s
.
ColumnTypeAffinity
(
2
),
"affinity"
)
assert
.
Equal
(
t
,
None
,
s
.
ColumnTypeAffinity
(
3
),
"affinity"
)
assert
.
Equal
(
t
,
Textual
,
s
.
ColumnTypeAffinity
(
4
),
"affinity"
)
assert
.
Equal
(
t
,
None
,
s
.
ColumnTypeAffinity
(
5
),
"affinity"
)
aff
,
err
:=
s
.
ColumnTypeAffinity
(
0
)
checkNoError
(
t
,
err
,
"%s"
)
assert
.
Equal
(
t
,
Integral
,
aff
,
"affinity"
)
aff
,
err
=
s
.
ColumnTypeAffinity
(
1
)
checkNoError
(
t
,
err
,
"%s"
)
assert
.
Equal
(
t
,
Real
,
aff
,
"affinity"
)
aff
,
err
=
s
.
ColumnTypeAffinity
(
2
)
checkNoError
(
t
,
err
,
"%s"
)
assert
.
Equal
(
t
,
Numerical
,
aff
,
"affinity"
)
aff
,
err
=
s
.
ColumnTypeAffinity
(
3
)
checkNoError
(
t
,
err
,
"%s"
)
assert
.
Equal
(
t
,
None
,
aff
,
"affinity"
)
aff
,
err
=
s
.
ColumnTypeAffinity
(
4
)
checkNoError
(
t
,
err
,
"%s"
)
assert
.
Equal
(
t
,
Textual
,
aff
,
"affinity"
)
aff
,
err
=
s
.
ColumnTypeAffinity
(
5
)
checkNoError
(
t
,
err
,
"%s"
)
assert
.
Equal
(
t
,
None
,
aff
,
"affinity"
)
}
func
TestExpressionTypeAffinity
(
t
*
testing
.
T
)
{
...
...
@@ -214,8 +226,16 @@ func TestExpressionTypeAffinity(t *testing.T) {
checkNoError
(
t
,
err
,
"%s"
)
defer
checkFinalize
(
s
,
t
)
assert
.
Equal
(
t
,
None
,
s
.
ColumnTypeAffinity
(
0
),
"affinity"
)
assert
.
Equal
(
t
,
None
,
s
.
ColumnTypeAffinity
(
1
),
"affinity"
)
assert
.
Equal
(
t
,
None
,
s
.
ColumnTypeAffinity
(
2
),
"affinity"
)
assert
.
Equal
(
t
,
None
,
s
.
ColumnTypeAffinity
(
3
),
"affinity"
)
aff
,
err
:=
s
.
ColumnTypeAffinity
(
0
)
checkNoError
(
t
,
err
,
"%s"
)
assert
.
Equal
(
t
,
None
,
aff
,
"affinity"
)
aff
,
err
=
s
.
ColumnTypeAffinity
(
1
)
checkNoError
(
t
,
err
,
"%s"
)
assert
.
Equal
(
t
,
None
,
aff
,
"affinity"
)
aff
,
err
=
s
.
ColumnTypeAffinity
(
2
)
checkNoError
(
t
,
err
,
"%s"
)
assert
.
Equal
(
t
,
None
,
aff
,
"affinity"
)
aff
,
err
=
s
.
ColumnTypeAffinity
(
3
)
checkNoError
(
t
,
err
,
"%s"
)
assert
.
Equal
(
t
,
None
,
aff
,
"affinity"
)
}
stmt.go
View file @
4d9000a7
This diff is collapsed.
Click to expand it.
stmt_test.go
View file @
4d9000a7
...
...
@@ -78,7 +78,8 @@ func TestInsertWithStatement(t *testing.T) {
defer
checkFinalize
(
rs
,
t
)
columnCount
=
rs
.
ColumnCount
()
assert
.
Equal
(
t
,
3
,
columnCount
,
"column count"
)
secondColumnName
:=
rs
.
ColumnName
(
1
)
secondColumnName
,
err
:=
rs
.
ColumnName
(
1
)
checkNoError
(
t
,
err
,
"error accessing column name: %s"
)
assert
.
Equal
(
t
,
"int_num"
,
secondColumnName
,
"column name"
)
if
checkStep
(
t
,
rs
)
{
...
...
@@ -230,7 +231,8 @@ func TestScanNull(t *testing.T) {
assert
.
T
(
t
,
null
,
"expected null value"
)
assert
.
Equal
(
t
,
false
,
bo
,
"expected false"
)
rb
,
null
:=
s
.
ScanRawBytes
(
0
)
rb
,
null
,
err
:=
s
.
ScanRawBytes
(
0
)
checkNoError
(
t
,
err
,
"scan error: %s"
)
assert
.
T
(
t
,
null
,
"expected null value"
)
assert
.
Equal
(
t
,
0
,
len
(
rb
),
"expected empty"
)
}
...
...
@@ -254,7 +256,8 @@ func TestScanNotNull(t *testing.T) {
assert
.
T
(
t
,
!
null
,
"expected not null value"
)
assert
.
Equal
(
t
,
"1"
,
*
ps
)
rb
,
null
:=
s
.
ScanRawBytes
(
0
)
rb
,
null
,
err
:=
s
.
ScanRawBytes
(
0
)
checkNoError
(
t
,
err
,
"scan error: %s"
)
assert
.
T
(
t
,
!
null
,
"expected not null value"
)
assert
.
Equal
(
t
,
1
,
len
(
rb
),
"expected not empty"
)
...
...
@@ -509,7 +512,8 @@ func TestScanBytes(t *testing.T) {
checkNoError
(
t
,
err
,
"prepare error: %s"
)
defer
checkFinalize
(
s
,
t
)
assert
.
T
(
t
,
checkStep
(
t
,
s
))
blob
,
_
:=
s
.
ScanBlob
(
0
)
blob
,
_
,
err
:=
s
.
ScanBlob
(
0
)
checkNoError
(
t
,
err
,
"scan error: %s"
)
assert
.
Equal
(
t
,
"test"
,
string
(
blob
))
}
...
...
@@ -528,9 +532,11 @@ func TestBindEmptyZero(t *testing.T) {
err
=
s
.
Scan
(
&
ps
,
&
zt
)
checkNoError
(
t
,
err
,
"scan error: %s"
)
assert
.
T
(
t
,
ps
==
nil
&&
zt
.
IsZero
(),
"null pointers expected"
)
_
,
null
:=
s
.
ScanValue
(
0
,
false
)
_
,
null
,
err
:=
s
.
ScanValue
(
0
,
false
)
checkNoError
(
t
,
err
,
"scan error: %s"
)
assert
.
T
(
t
,
null
,
"null string expected"
)
_
,
null
=
s
.
ScanValue
(
1
,
false
)
_
,
null
,
err
=
s
.
ScanValue
(
1
,
false
)
checkNoError
(
t
,
err
,
"scan error: %s"
)
assert
.
T
(
t
,
null
,
"null time expected"
)
}
...
...
@@ -556,9 +562,11 @@ func TestBindEmptyZeroNotTransformedToNull(t *testing.T) {
err
=
s
.
Scan
(
&
st
,
&
zt
)
checkNoError
(
t
,
err
,
"scan error: %s"
)
assert
.
T
(
t
,
len
(
st
)
==
0
&&
zt
.
IsZero
(),
"null pointers expected"
)
_
,
null
:=
s
.
ScanValue
(
0
,
false
)
_
,
null
,
err
:=
s
.
ScanValue
(
0
,
false
)
checkNoError
(
t
,
err
,
"scan error: %s"
)
assert
.
T
(
t
,
!
null
,
"empty string expected"
)
_
,
null
=
s
.
ScanValue
(
1
,
false
)
_
,
null
,
err
=
s
.
ScanValue
(
1
,
false
)
checkNoError
(
t
,
err
,
"scan error: %s"
)
assert
.
T
(
t
,
!
null
,
"zero time expected"
)
}
...
...
@@ -574,8 +582,12 @@ func TestColumnType(t *testing.T) {
expectedAffinities
:=
[]
Affinity
{
Integral
,
Real
,
Integral
,
Textual
}
for
col
:=
0
;
col
<
s
.
ColumnCount
();
col
++
{
//println(col, s.ColumnName(col), s.ColumnOriginName(col), s.ColumnType(col), s.ColumnDeclaredType(col))
assert
.
Equal
(
t
,
Null
,
s
.
ColumnType
(
col
),
"column type"
)
assert
.
Equal
(
t
,
expectedAffinities
[
col
],
s
.
ColumnTypeAffinity
(
col
),
"column type affinity"
)
ct
,
err
:=
s
.
ColumnType
(
col
)
checkNoError
(
t
,
err
,
"column type error: %s"
)
assert
.
Equal
(
t
,
Null
,
ct
,
"column type"
)
cta
,
err
:=
s
.
ColumnTypeAffinity
(
col
)
checkNoError
(
t
,
err
,
"column type affinity error: %s"
)
assert
.
Equal
(
t
,
expectedAffinities
[
col
],
cta
,
"column type affinity"
)
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment