A fixed-size dynamic array


Background

I implemented the historic std::dynarray according to the specification under the name dynamic_array in C++17. dynamic_array doesn’t attempt to get allocated on stack storage.

The most interesting part is the allocator support. Unlike other containers, dynamic_array does not take an allocator as a template parameter. But it supports construction from an arbitrary allocator, and it has to call the appropriate allocator on destruction. As such, the allocator has to be stored with the help of type erasure.

At first I thought of using std::any to hold the allocator. However, there is a problem: std::any does not have a visit functionality, we can’t get the type of the allocator back, thus unable to call std::allocator_traits<A>::destroy.

As such, my approach is to use a std::function. A lambda is generated for each construction from an allocator, which captures the allocator by copy and calls the correct destroy function. Admittedly, this is one of the few times I find a meaningful usage for mutable lambdas.

Code

Here’s the header dynamic_array.hpp:

// C++17 fixed-size dynamic array  #ifndef INC_DYNAMIC_ARRAY_HPP_akMQiHuI0M #define INC_DYNAMIC_ARRAY_HPP_akMQiHuI0M  #include <algorithm> #include <cstddef> #include <cstdint> #include <functional> #include <initializer_list> #include <iterator> #include <memory> #include <type_traits>  namespace LF_lib {    template <class T>   class dynamic_array {   public:     using value_type = T;     using size_type = std::size_t;     using difference_type = std::ptrdiff_t;      using reference = T&;     using const_reference = const T&;     using pointer = T*;     using const_pointer = const T*;      using iterator = T*;     using const_iterator = const T*;     using reverse_iterator = std::reverse_iterator<iterator>;     using const_reverse_iterator = std::reverse_iterator<const_iterator>;      // default-initializes the elements     explicit dynamic_array(std::size_t n)       :dynamic_array{n, std::allocator<T>{}}     {     }      template <class A>     dynamic_array(std::size_t n, const A& a)       :count{n}     {       if (count == 0) {         register_empty_cleanup();         return;       }        A alloc = a;       elems = std::allocator_traits<A>::allocate(alloc, count);       T* p = begin();       try {         register_cleanup(alloc);         for (; p != end(); ++p)           std::allocator_traits<A>::construct(alloc, p);       } catch (...) {         for (T* q = begin(); q != p; ++q)           std::allocator_traits<A>::destroy(alloc, q);         std::allocator_traits<A>::deallocate(alloc, elems, count);         throw;       }     }      dynamic_array(std::size_t n, const T& value)       :dynamic_array{n, value, std::allocator<T>{}}     {     }      template <class A>     dynamic_array(std::size_t n, const T& value, const A& a)       :count{n}     {       if (count == 0) {         register_empty_cleanup();         return;       }        A alloc = a;       elems = std::allocator_traits<A>::allocate(alloc, count);       T* p = begin();       try {         register_cleanup(alloc);         for (; p != end(); ++p)           std::allocator_traits<A>::construct(alloc, p, value);       } catch (...) {         for (T* q = begin(); q != p; ++q)           std::allocator_traits<A>::destroy(alloc, q);         std::allocator_traits<A>::deallocate(alloc, elems, count);         throw;       }     }      dynamic_array(const dynamic_array& other)       :dynamic_array{other, std::allocator<T>{}}     {     }      template <class A>     dynamic_array(const dynamic_array& other, const A& a)       :count{other.size()}     {       if (count == 0) {         register_empty_cleanup();         return;       }        A alloc = a;       elems = std::allocator_traits<A>::allocate(alloc, count);       T* p = begin();       try {         register_cleanup(alloc);         for (const T* q = other.cbegin(); p != cend(); ++p, ++q)           std::allocator_traits<A>::construct(alloc, p, *q);       } catch (...) {         for (T* q = begin(); q != p; ++q)           std::allocator_traits<A>::destroy(alloc, q);         std::allocator_traits<A>::deallocate(alloc, elems, count);         throw;       }     }      dynamic_array(std::initializer_list<T> init)       :dynamic_array{init, std::allocator<T>{}}     {     }      template <class A>     dynamic_array(std::initializer_list<T> init, const A& a)       :count{init.size()}     {       if (count == 0) {         register_empty_cleanup();         return;       }        A alloc = a;       elems = std::allocator_traits<A>::allocate(alloc, count);       T* p = begin();       try {         register_cleanup(alloc);         for (const T* q = init.begin(); p != end(); ++p, ++q)           std::allocator_traits<A>::construct(alloc, p, *q);       } catch (...) {         for (T* q = begin(); q != p; ++q)           std::allocator_traits<A>::destroy(alloc, q);         std::allocator_traits<A>::deallocate(alloc, elems, count);         throw;       }     }      ~dynamic_array()     {       cleanup(elems, count);     }      dynamic_array& operator=(const dynamic_array&) = delete;     dynamic_array& operator=(dynamic_array&&) = delete;            T& at(std::size_t index)       { check(index); return elems[index]; }     const T& at(std::size_t index) const { check(index); return elems[index]; }            T& operator[](std::size_t index)       { return elems[index]; }     const T& operator[](std::size_t index) const { return elems[index]; }            T& front()       { return elems[0]; }     const T& front() const { return elems[0]; }            T& back()       { return elems[count - 1]; }     const T& back() const { return elems[count - 1]; }            T* data()       noexcept { return elems; }     const T* data() const noexcept { return elems; }            iterator  begin()       noexcept { return elems; }     const_iterator  begin() const noexcept { return elems; }     const_iterator cbegin() const noexcept { return begin(); }            iterator  end()       noexcept { return elems + count; }     const_iterator  end() const noexcept { return elems + count; }     const_iterator cend() const noexcept { return end(); }            reverse_iterator  rbegin()       noexcept { return end(); }     const_reverse_iterator  rbegin() const noexcept { return end(); }     const_reverse_iterator crbegin() const noexcept { return rbegin(); }            reverse_iterator  rend()       noexcept { return begin(); }     const_reverse_iterator  rend() const noexcept { return begin(); }     const_reverse_iterator crend() const noexcept { return rend(); }      bool empty() const noexcept { return size != 0; }     std::size_t size() const noexcept { return count; }      std::size_t max_size() const noexcept     {       return SIZE_MAX / sizeof(T);     }      void fill(const T& value)     {       std::fill(begin(), end(), value);     }    private:     T* elems = nullptr;     std::size_t count;     std::function<void(T*, std::size_t)> cleanup;      void register_empty_cleanup()     {       cleanup = [](T*, std::size_t) {};     }      template <class A>     void register_cleanup(A& alloc)     {       cleanup = [alloc](T* elems, std::size_t count) mutable {         T* it = elems;         for (std::size_t i = 0; i < count; ++i)           std::allocator_traits<A>::destroy(alloc, it++);         std::allocator_traits<A>::deallocate(alloc, elems, count);       };     }      void check(std::size_t index) const     {       if (index >= count)         throw std::out_of_range{"LF_lib::dynamic_array out of range"};     }   };    template <class T>   bool operator==(const dynamic_array<T>& lhs, const dynamic_array<T>& rhs)   {     return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());   }    template <class T>   bool operator!=(const dynamic_array<T>& lhs, const dynamic_array<T>& rhs)   {     return !(lhs == rhs);   }    template <class T>   bool operator< (const dynamic_array<T>& lhs, const dynamic_array<T>& rhs)   {     return std::lexicographical_compare(lhs.begin(), lhs.end(),                                         rhs.begin(), rhs.end());   }    template <class T>   bool operator<=(const dynamic_array<T>& lhs, const dynamic_array<T>& rhs)   {     return !(rhs < lhs);   }    template <class T>   bool operator> (const dynamic_array<T>& lhs, const dynamic_array<T>& rhs)   {     return rhs < lhs;   }    template <class T>   bool operator>=(const dynamic_array<T>& lhs, const dynamic_array<T>& rhs)   {     return !(lhs < rhs);   }  }  namespace std {    template <class T, class A>   struct uses_allocator<LF_lib::dynamic_array<T>, A>     :std::true_type { };  }  #endif 

And here’s an example on its usage, showing how the allocators work under the hood:

#include <iomanip> #include <iostream> #include <numeric> #include <string> #include <type_traits>  #include "dynamic_array.hpp"  using LF_lib::dynamic_array;  template <typename T> class Tracing_alloc :private std::allocator<T> {   using Base = std::allocator<T>; public:   using value_type = T;    T* allocate(std::size_t n)   {     std::cerr << "allocate(" << n << ")\n";     return Base::allocate(n);   }    void deallocate(T* ptr, std::size_t n)   {     std::cerr << "deallocate(" << static_cast<void*>(ptr) << ", "               << n << ")\n";     Base::deallocate(ptr, n);   }    template <typename... Args>   void construct(T* ptr, Args&&... args)   {     std::cerr << "construct(" << ptr << ", args...)\n";     std::allocator_traits<Base>::construct(*this, ptr, args...);   }    void destroy(T* ptr)   {     std::cerr << "destroy(" << ptr << ")\n";     std::allocator_traits<Base>::destroy(*this, ptr);   } };  template <typename T> bool operator==(const Tracing_alloc<T>&, const Tracing_alloc<T>&) {   return true; }  template <typename T> bool operator!=(const Tracing_alloc<T>&, const Tracing_alloc<T>&) {   return false; }  class Construct_throw { public:   Construct_throw()   {     static int i = 0;     if (i++ > 3)       throw std::exception{};   } };  void test(std::size_t n) {   dynamic_array<std::string> arr{n, Tracing_alloc<std::string>{}};   for (auto& x : arr)     x = "a";   std::inclusive_scan(arr.begin(), arr.end(), arr.begin(), std::plus<>{});   for (const auto& x : arr)     std::cout << std::quoted(x) << " ";   std::cout << "\n";    dynamic_array<std::string> arr2{arr, Tracing_alloc<std::string>{}};   for (const auto& x : arr2)     std::cout << std::quoted(x) << " ";   std::cout << "\n";    dynamic_array<std::string> arr3{{"foo", "bar", "baz"},       Tracing_alloc<std::string>{}};   for (const auto& x : arr3)     std::cout << std::quoted(x) << " ";   std::cout << "\n";    dynamic_array<Construct_throw> arr4{n, Tracing_alloc<Construct_throw>{}}; }  int main() try {   test(0);   test(10); } catch (...) {   return 1; } 

Here’s the output I got: (the initial empty lines are intentional)

   allocate(3) construct(000001CE3ADE8F60, args...) construct(000001CE3ADE8F80, args...) construct(000001CE3ADE8FA0, args...) "foo" "bar" "baz"  destroy(000001CE3ADE8F60) destroy(000001CE3ADE8F80) destroy(000001CE3ADE8FA0) deallocate(000001CE3ADE8F60, 3) allocate(10) construct(000001CE3ADEC130, args...) construct(000001CE3ADEC150, args...) construct(000001CE3ADEC170, args...) construct(000001CE3ADEC190, args...) construct(000001CE3ADEC1B0, args...) construct(000001CE3ADEC1D0, args...) construct(000001CE3ADEC1F0, args...) construct(000001CE3ADEC210, args...) construct(000001CE3ADEC230, args...) construct(000001CE3ADEC250, args...) "a" "aa" "aaa" "aaaa" "aaaaa" "aaaaaa" "aaaaaaa" "aaaaaaaa" "aaaaaaaaa" "aaaaaaaaaa"  allocate(10) construct(000001CE3ADEDED0, args...) construct(000001CE3ADEDEF0, args...) construct(000001CE3ADEDF10, args...) construct(000001CE3ADEDF30, args...) construct(000001CE3ADEDF50, args...) construct(000001CE3ADEDF70, args...) construct(000001CE3ADEDF90, args...) construct(000001CE3ADEDFB0, args...) construct(000001CE3ADEDFD0, args...) construct(000001CE3ADEDFF0, args...) "a" "aa" "aaa" "aaaa" "aaaaa" "aaaaaa" "aaaaaaa" "aaaaaaaa" "aaaaaaaaa" "aaaaaaaaaa"  allocate(3) construct(000001CE3ADE8F60, args...) construct(000001CE3ADE8F80, args...) construct(000001CE3ADE8FA0, args...) "foo" "bar" "baz"  allocate(10) construct(000001CE3ADE8CC0, args...) construct(000001CE3ADE8CC1, args...) construct(000001CE3ADE8CC2, args...) construct(000001CE3ADE8CC3, args...) construct(000001CE3ADE8CC4, args...) destroy(000001CE3ADE8CC0) destroy(000001CE3ADE8CC1) destroy(000001CE3ADE8CC2) destroy(000001CE3ADE8CC3) deallocate(000001CE3ADE8CC0, 10) destroy(000001CE3ADE8F60) destroy(000001CE3ADE8F80) destroy(000001CE3ADE8FA0) deallocate(000001CE3ADE8F60, 3) destroy(000001CE3ADEDED0) destroy(000001CE3ADEDEF0) destroy(000001CE3ADEDF10) destroy(000001CE3ADEDF30) destroy(000001CE3ADEDF50) destroy(000001CE3ADEDF70) destroy(000001CE3ADEDF90) destroy(000001CE3ADEDFB0) destroy(000001CE3ADEDFD0) destroy(000001CE3ADEDFF0) deallocate(000001CE3ADEDED0, 10) destroy(000001CE3ADEC130) destroy(000001CE3ADEC150) destroy(000001CE3ADEC170) destroy(000001CE3ADEC190) destroy(000001CE3ADEC1B0) destroy(000001CE3ADEC1D0) destroy(000001CE3ADEC1F0) destroy(000001CE3ADEC210) destroy(000001CE3ADEC230) destroy(000001CE3ADEC250) deallocate(000001CE3ADEC130, 10) 

Of course, you may get completely different addresses.

AOT build silently ignores dynamic route configuration

When route configuration contains some shared static data, that data will be ignored during AOT compilation. However it works as expected with JIT compiler.

  data: {     trackingArea: 'some-feature',     product: 'some-feature'   } };  // `data` property will not be present with AOT const routes: Routes = [   { path: '', pathMatch: 'full', component: HomeComponent, ...sharedConfig },   { path: '**', component: NotFoundComponent, ...sharedConfig } ];  @NgModule({   imports: [RouterModule.forRoot(routes)],   exports: [RouterModule] }) export class AppRoutingModule { } 

Magento2 Dynamic Rows not providing position with data array

I have created a dynamicRows component for Customer Edit Form. For some reason, if I set visible to false on the field “position”, when I submit a new record, position is never part of the data array.

<field name="position">                 <argument name="data" xsi:type="array">                     <item name="config" xsi:type="array">                         <!-- item name="source" xsi:type="string">customer</item -->                         <item name="dataType" xsi:type="string">number</item>                         <item name="formElement" xsi:type="string">input</item>                         <item name="componentType" xsi:type="string">field</item>                         <item name="label" xsi:type="string" translate="true">Position</item>                         <item name="dataScope" xsi:type="string">position</item>                         <item name="visible" xsi:type="boolean">false</item>                     </item>                 </argument>             </field> 

When the field is visible, then the key “position” is provided and everything works perfect, but I prefer this field to stay hidden. This only happens when adding new row.

Any thoughts?

Safe dynamic SQL for generic search

Prompted by discussion about SQL injection, I wanted to put a proof of concept forward to get feedback about whether this is in fact safe and protected against SQL injection or other malicious use. For good reference on the subject of constructing a dynamic search with dynamic SQL, I’d probably look there.

This is meant to be a proof of concept, not a complete working solution to illustrate how we can accept text input from users but handle it as if it were parameterized properly.

The assumptions are as follows:

1) We don’t want to run code client-side — in theory, this could have been done in a middle tier as some kind of API. However, even if there were a middle tier API endpoint, it does no good if it does not properly parameterize the query it makes on users’ behalf. Furthermore, having it in SQL means that it is now generic to any clients who may need the functionality but at expense of poor portability. This will likely work only on Microsoft SQL Server, not on other database vendors, at least not without significant modifications.

2) Under no circumstances should the users be allowed to write the dynamic SQL, whether directly or indirectly. The only thing that should write the dynamic SQL is our code, without any user’s inputs. That means taking additional indirection to ensure that users’ input cannot become a part of the dynamic SQL being assembled.

3) We assume that the users only need to search a single table, wants all columns, but may want to filter on any columns. This is only to simplify the proof of the concept – there is no technical reason why it can’t do more, provided that the practices outlined in the proof of concept is rigorously followed.

Helper Function for data types

We first need a function to help us with building a formatted data type because the sys.types don’t present the information in most friendly manner for writing a parameter. While this could be more sophisticated, this suffices for most common cases:

CREATE OR ALTER FUNCTION dbo.ufnGetFormattedDataType (     @DataTypeName sysname,     @Precision int,     @Scale int,     @MaxLength int ) RETURNS nvarchar(255)  WITH SCHEMABINDING AS BEGIN     DECLARE @Suffix nvarchar(15);      SET @Suffix = CASE          WHEN @DataTypeName IN (N'nvarchar', N'nchar', N'varchar', N'char', N'varbinary', N'binary')         THEN CONCAT(N'(', IIF(@MaxLength = -1, N'MAX', CAST(@MaxLength AS nvarchar(12))), ')')          WHEN @DataTypeName IN (N'decimal', N'numeric')         THEN CONCAT(N'(', @Precision, N', ', @Scale, N')')          WHEN @DataTypeName IN (N'datetime2', N'datetimeoffset', N'time')         THEN CONCAT(N'(', @Scale, N')')          ELSE N''     END;      RETURN CONCAT(@DataTypeName, @Suffix); END; 

Main dynamic search procedure

With the function, we can then build our main procedure for creating the dynamic SQL to support generic search:

CREATE OR ALTER PROCEDURE dbo.uspDynamicSearch (     @TableName sysname,     @ParameterXml xml  ) AS BEGIN     DECLARE @stableName sysname,             @stableId int,             @err nvarchar(4000)     ;      SELECT           @stableName = o.Name,         @stableId = o.object_id     FROM sys.objects AS o     WHERE o.name = @tableName;      IF @stableName IS NULL     OR @stableId IS NULL     BEGIN         SET @err = N'Invalid table name specified.';         THROW 50000, @err, 1;         RETURN -1;     END;      WITH BaseData AS (         SELECT             x.value(N'@Name', N'sysname') AS ParameterName,             x.value(N'@Value', N'nvarchar(MAX)') AS ParameterValue         FROM @ParameterXml.nodes(N'/l/p') AS t(x)     )     SELECT         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS Id,         c.name AS ColumnName,         d.ParameterValue AS ParameterValue,         c.user_type_id AS DataTypeId,         t.name AS DataTypeName,         c.max_length AS MaxLength,         c.precision AS Precision,         c.scale AS Scale,         dbo.ufnGetFormattedDataType(t.name, c.precision, c.scale, c.max_length) AS ParameterDataType     INTO #ParameterData     FROM BaseData AS d     INNER JOIN sys.columns AS c         ON d.ParameterName = c.name     INNER JOIN sys.types AS t         ON c.user_type_id = t.user_type_id     WHERE c.object_id = @stableId;      DECLARE @Sql nvarchar(MAX) = CONCAT(N'SELECT * FROM ', @stableName);      IF EXISTS (         SELECT NULL         FROM #ParameterData     )     BEGIN         DECLARE @And nvarchar(5) = N' AND ';          SET @Sql += CONCAT(N' WHERE ', STUFF((             SELECT                  CONCAT(@And, QUOTENAME(d.ColumnName), N' = @P', d.Id)             FROM #ParameterData AS d             FOR XML PATH(N'')         ), 1, LEN(@And), N''));          DECLARE @Params nvarchar(MAX) = CONCAT(N'DECLARE ', STUFF((             SELECT                 CONCAT(N', @P', d.Id, N' ', d.ParameterDataType, N' = ( SELECT CAST(d.ParameterValue AS ', d.ParameterDataType, N') FROM #ParameterData AS d WHERE d.Id = ', d.Id, N') ')             FROM #ParameterData AS d             FOR XML PATH(N'')         ), 1, 2, N''), N';');          SET @Sql = @Params + @Sql;     END;      EXEC sys.sp_executesql @Sql; END; 

Analysis

Let’s go over the procedures in parts to elaborate the reasoning behind the design, starting with the parameters.

@TableName sysname, @ParameterXml xml  

The table name is self-evident but we require that the users provide their search conditions as a XML document. It doesn’t have to be a XML document; JSON would work as well (provided that you’re using a recent version of SQL Server). The point is that it must be a well-defined format with native support for parsing the contents. A sample XML may look something like this:

<l>   <p Name="First Name" Value="Martin" />   <p Name="Last Name" Value="O’Donnell" /> </l> 

The XML is basically a (l)ist of the (p)arameters in name-value pairs.

We have to validate both parameters. First is easily done:

SELECT       @stableName = o.Name,     @stableId = o.object_id FROM sys.objects AS o WHERE o.name = @TableName; 

Because we do not want users’ inputs to go directly into the dynamic SQL, we use a separate variable, @stableName which would be same value as the @TableName but only if the user isn’t malicious and tried to sneak in extra characters. Since we filter it through the sys.objects, that implicitly enforces SQL Server’s identifier rules and thus validate that the input is valid.

For the parameters, we need some more work, so we need to load into a temporary table.

WITH BaseData AS (     SELECT         x.value(N'@Name', N'sysname') AS ParameterName,         x.value(N'@Value', N'nvarchar(MAX)') AS ParameterValue     FROM @ParameterXml.nodes(N'/l/p') AS t(x) ) SELECT     ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS Id,     c.name AS ColumnName,     d.ParameterValue AS ParameterValue,     c.user_type_id AS DataTypeId,     t.name AS DataTypeName,     c.max_length AS MaxLength,     c.precision AS Precision,     c.scale AS Scale,     dbo.ufnGetFormattedDataType(t.name, c.precision, c.scale, c.max_length) AS ParameterDataType INTO #ParameterData FROM BaseData AS d INNER JOIN sys.columns AS c     ON d.ParameterName = c.name INNER JOIN sys.types AS t     ON c.user_type_id = t.user_type_id WHERE c.object_id = @stableId; 

In addition to validating the column names we want to use for filters, we collect metadata from the sys.columns and sys.types. Note that the XML itself can’t be used to tell us what the data types the user wants to use. That would be a vector for malicious attack so we must rely on the information from the catalog views, accepting only the values directly from the XML supplied by the user.

Note the ROW_NUMBER() generating the IDs of the parameters. That is important as will be seen later on.

DECLARE @Sql nvarchar(MAX) = CONCAT(N'SELECT * FROM ', @stableName);

We build our first part of the dynamic SQL. We assume that it’s OK to allow the users to select entire table, though that might be dickish if there’s lot of records. In a complete solution, it might be more prudent to have a TOP 100 or something like that.

Going forward, We’ll assume that we have a set of parameters that we need to filter on.

SET @Sql += CONCAT(N' WHERE ', STUFF((     SELECT          CONCAT(@And, QUOTENAME(d.ColumnName), N' = @P', d.Id)     FROM #ParameterData AS d     FOR XML PATH(N'') ), 1, LEN(@And), N'')); 

Here, we abuse the FOR XML PATH to provide a concatenation of the filter predicate for the WHERE clause. Using the sample XML above, the output would have been something like WHERE [First Name] = @P1 AND [Last Name] = @P2. Note the horrid naming of columns, with spaces in it, to show the value of QUOTENAME to ensure that even in a crappy database schema, we can avoid getting an error with a iffy identifier.

DECLARE @Params nvarchar(MAX) = CONCAT(N'DECLARE ', STUFF((     SELECT         CONCAT(N', @P', d.Id, N' ', d.ParameterDataType, N' = ( SELECT CAST(d.ParameterValue AS ', d.ParameterDataType, N') FROM #ParameterData AS d WHERE d.Id = ', d.Id, N') ')     FROM #ParameterData AS d     FOR XML PATH(N'') ), 1, 2, N''), N';'); 

This is the closest the user’s input can get — we would read from the same temporary table we created and assign to a parameter we create ourselves, with a CAST. Note that we could have used a TRY_CAST to avoid a runtime error but I would argue that an error needs to occur if the users put in bad input. In a complete solution, the procedure could be wrapped in a TRY/CATCH block to sanitize the error message somehow.

Again using the XML example from above, it’d come out something like this:

DECLARE @P1 varchar(100) = SELECT CAST(d.ParameterValue AS varchar(100)) FROM #ParameterData AS d WHERE d.Id = 1; 

Note that we did not even use the name that the users provided to us; we used a numeric ID which was concatenated by our own code. Furthermore, the code reads from the temporary table and CAST it into the parameter we want it to be. That makes it easier for us to handle different data types for various parameters the users may send to us but without actually concatenating the values they provide to us to our dynamic SQL.

Once we have that, we concatenate the assignments to the @Sql and execute it:

EXEC sys.sp_executesql @Sql; 

Note that we didn’t use the @params parameter of the sp_executesql — there’s no parameters we can really pass in since the parameters are in a temporary table, which was why we used assignments inside the dynamic SQL to move the user’s input from a XML document to a parameter within the dynamic SQL.

Can this be broke?

As mentioned, the discussion about SQL injection made me wonder if I may have missed something or made an assumption where the malicious user could still maange to circumvent the layers of indirection I’ve put in and inject their nasty little SQL?

PHP – PDO – Elegant and secure way to create dynamic query

I want to create a dynamic query to display all the invoices if the user has moderator rank and when the user is a simple member, only his invoices

 public function getAllBill($  user_rank, $  user_id){    $  sql = 'SELECT * FROM invoice_user   INNER JOIN users on users.user_id = invoice_user.user_id';    $  sql_clause = 'WHERE user_id = :user_id)';   $  sql_group  = 'GROUP BY invoice_number ORDER BY invoicedate DESC';    if ($  user_rank === 'member') {     $  final_sql = $  sql.' '.$  sql_clause.' '.$  sql_group;     $  parameters = array(':user_id' => $  user_id);   }    else if ($  user_rank === 'moderator'){     $  final_sql = $  sql.' '.$  sql_group;     $  parameters = array();   }   else {     $  error = TRUE;   }    if (!isset($  error)) {     $  request = $  this->bdd->prepare($  final_sql);     $  request->execute($  parameters);     return $  request->fetchAll();   } else return array();  } 

I would like to know if there was a more elegant way to do this but especially to know if everything is safe knowing that the rank and the ID come from the user session ($ _SESSION ['rank'], $ _SESSION ['id'])

Does it pose a problem not to put my parameter table in a condition?

PS : I use MySQL

Dynamic Bootstrap 4 modal using JavaScript OOP

I have created dynamic Bootstrap 4 modal using JavaScript OOP. Please verify and give your reviews how I can improve the code. I have passed four parameters to create a dynamic modal:

  1. openPopup class (for click)
  2. data-title (dynamic title)
  3. data-href (dynamic load html in modal)
  4. data-target (target id if i have multiple modal)
    class Modal{           constructor(id,url,title){              this.id = id;              this.url = url;              this.title = title;          }         }         class UI{              static addModal(){              $  ('body').on('click', '.openPopup', function(e) {              const id = $  (this).attr('data-target'),              url = $  (this).attr('data-href'),              title = $  (this).attr('data-title')              const modal = new Modal(id, url, title);              console.log(modal)              if($  ('#'+ modal.id).length){               $  ('#'+ modal.id).modal({show:true});              }             else{             let html = `            <div class="modal fade" id="$  {modal.id}" tabindex="-1"         role="dialog">           <div class="modal-dialog modal-dialog-centered" role="document">         <div class="modal-content">           <div class="modal-header">             <h5 class="modal-title" id="exampleModalLongTitle">$  {modal.title}             </h5>           <button type="button" class="close" data-dismiss="modal" aria-              label="Close">               <span aria-hidden="true">&times;</span>             </button>           </div>           <div id="$  {modal.id}body" class="modal-body">           </div>           <div class="modal-footer">             <button type="button" class="btn btn-secondary" data-                  dismiss="modal">Close</button>             <button type="button" id="save" class="btn btn-primary">Save         changes</button>           </div>         </div>         </div>          </div>`;         $  ('body').append(html);         $  ('#'+ modal.id + 'body').load(modal.url,function(){        $  ('#'+ modal.id).modal({show:true});        });          }        })        }}         class ModalApp{            static init(){              console.log('App Started...');             UI.addModal()             }         }         ModalApp.init();
   <button type="button" class="btn btn-primary openPopup"  data-title="Test    about" data-href="partial/about.html" data-toggle="modal" data-    target="myModal1">     Launch demo about    </button>

See the fiddle below

JSfiddle

How to find Maximum perimeter of rectangle in a grid with obstacles? (Dynamic Programming)

Can someone tell me what am I doing wrong?

Problem: https://codeforces.com/contest/22/problem/B

Editorial: https://codeforces.com/blog/entry/507 ( I followed the DP solution O((n*m)^2) )

My approach: rectangle with coordinates (x1, y1, x2, y2) is correct if and only if rectangles (x1, y1, x2-1, y2) and (x1, y1, x2, y2-1) are correct, and board[x2][y2] = ‘0’.

If it is correct then find it’s perimeter and if it’s greater then answer then answer=perimeter ie ans=max(ans,dp[i][j][p][q])

so dp[ i ][ j ][ i ][ j ]=1 for all i,j when v[i][j]==0. Because from point p1 to point p1, ie the same point always have a perimeter is the base case.

signed main(){     int r,c;cin>>r>>c;     vector<vi> v(r,vi(c));//2d array v[r][c]     bool dp[25][25][25][25]={false};//i,j to p,q     for(int i=0;i<r;i++){         string s;cin>>s;         for(int j=0;j<c;j++){             v[i][j]=(s[j]-'0');             if(v[i][j]==0)dp[i][j][i][j]=true;         }     }     int ans=-1;     for(int i=0;i<r;i++){         for(int j=0;j<c;j++){             for(int p=i;p<r;p++){                 for(int q=j;q<c;q++){                     //i,j to p,q , 0,0 0,2, afrom 1 to p, b from 1 to q                     if(!(i==p && j==q)){                         if(p-1>=0 && q-1>=0)                             dp[i][j][p][q]=(dp[i][j][p-1][q] && dp[i][j][p][q-1] && (v[p][q]==0));                         if(dp[i][j][p][q]==true){                             ans=max(ans,2*(p-i+q-j+2));                         }                     }                 }             }         }     }     cout<<ans; } 

Is This A Dynamic Programming Problem?

Given Two arrays both of length n, you have to choose exactly k values from the array 1 and n-k values from the other array, such that the sum of these values is maximum.

I have encountered this type of question in many places but never able to solve it, and I always have an Intuition that this is a dynamic programming problem but never able to prove it. I do not quite understand If there exist a dynamic solution or not?

My Experience in DP- 1Month, also my first question here not sure If I managed to follow the rules 😐