www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - mysql-native ResultRange + map

reply crimaniak <crimaniak gmail.com> writes:
Hi all!

After some hard time with debugging, I found ResultRange returned 
by query() and Prepared::query() of mysql-native package can't be 
combined with map() because after map() it becomes empty 
resultset.

Code (conn.queryRows just a wrapper for query(Connections, sql) ):

	immutable sql = "SELECT id FROM "~tableName~" ORDER BY id";

	conn.queryRows(sql).each!(row => writeln("each:", 
row[0].to!string));

	string[] applied = conn.queryRows(sql).map!(row => 
row[0].to!string).array;
	writeln("applied:", applied);

	foreach(row; conn.queryRows(sql))
		writeln("foreach: ", row[0].to!string);

	conn.queryRows(sql).map!(row => row[0].to!string).each!(row => 
writeln("map-each:", row));

	foreach(row; conn.queryRows(sql).map!(row => row[0].to!string))
		writeln("foreach-map: ", row);

	stdout.flush;

Result:
SELECT id FROM versionupdate ORDER BY id
each:.Script20161013_create_database
each:.Script20161221_sites_table
each:.Script20161227_update_users_devices
each:.Script20170121_ownerid
each:.Script20170124_create_clients
each:.Script20170213_no_unique_site_name
each:.Script20170215_remove_site_sn
each:.Script20170228_remove_site_index
each:.Script20170301_add_linkNo
each:.Script20170301_fix_sites_indexes
each:.Script20170310_demo_client
each:.Script20170513_max_dev_number
SELECT id FROM versionupdate ORDER BY id
applied:[]
SELECT id FROM versionupdate ORDER BY id
foreach: .Script20161013_create_database
foreach: .Script20161221_sites_table
foreach: .Script20161227_update_users_devices
foreach: .Script20170121_ownerid
foreach: .Script20170124_create_clients
foreach: .Script20170213_no_unique_site_name
foreach: .Script20170215_remove_site_sn
foreach: .Script20170228_remove_site_index
foreach: .Script20170301_add_linkNo
foreach: .Script20170301_fix_sites_indexes
foreach: .Script20170310_demo_client
foreach: .Script20170513_max_dev_number
SELECT id FROM versionupdate ORDER BY id
SELECT id FROM versionupdate ORDER BY id

As you see simple each() and foreach() works, but all examples 
with map() involved always empty. Can anybody explain such 
strange behavior?
Jul 05 2017
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 7/5/17 12:04 PM, crimaniak wrote:
 Hi all!
 
 After some hard time with debugging, I found ResultRange returned by 
 query() and Prepared::query() of mysql-native package can't be combined 
 with map() because after map() it becomes empty resultset.
 
[snip]
 As you see simple each() and foreach() works, but all examples with 
 map() involved always empty. Can anybody explain such strange behavior?
 
Because of the temporary copy likely inside map closes the connection. See the bug I reported: https://github.com/mysql-d/mysql-native/issues/117 I work around this in my code by moving the temporary copy. But I'm sorry to say you likely will not be able to fix map. I think Nick's comment is interesting, "Seems that using struct dtors without refcounting should in general be regarded as a code smell?" It's a good question. I've also always added ref counting when wanting to "auto close" a struct's resources. In fact, I can't really think of a good use of destructors for structs that isn't for reference counting itself. -Steve
Jul 11 2017
parent crimaniak <crimaniak gmail.com> writes:
On Tuesday, 11 July 2017 at 22:46:00 UTC, Steven Schveighoffer 
wrote:
 On 7/5/17 12:04 PM, crimaniak wrote:
...
 Because of the temporary copy likely inside map closes the 
 connection.

 See the bug I reported: 
 https://github.com/mysql-d/mysql-native/issues/117
Yes, it seems to be the same issue. (BTW, then I tried filter() just for curiosity and have the same problem).
 I work around this in my code by moving the temporary copy. But 
 I'm sorry to say you likely will not be able to fix map.
I have WEB application (no big recordsets to transfer), so, for now, I "fix" it inside of my sql wrapper: just load recordset to an array and give it instead of ResultRange. I don't like it, but it works and all shit is localized in one place.
 I think Nick's comment is interesting, "Seems that using struct 
 dtors without refcounting should in general be regarded as a 
 code smell?"

 It's a good question. I've also always added ref counting when 
 wanting to "auto close" a struct's resources. In fact, I can't 
 really think of a good use of destructors for structs that 
 isn't for reference counting itself.
I don't think so. There is architecture problem: non-copyable by nature resource represented by copyable struct. We need non-copyable class/object semantics here or have to emulate it if using the struct to have the correct behavior. It's fully o.k. to get some resources required by _this exact copy_ of struct in the constructor and then release it in the destructor. For example of good use of destructors: position in some game, requires non-fixed space to store itself. We want to make copies of positions, apply some movies to them and then make copies again to search in positions tree. Copy constructor will malloc some space and copy source position data, the destructor will free this space, and we don't need reference counting here.
Jul 11 2017