问:
Docker filling up storage on macOS
(Post created on Oct 05 '16)

I noticed that every time I run an image and delete it, my system doesn't return to the original amount of available space.

The lifecycle I'm applying to my containers is:

```<code>> docker build ...
> docker run CONTAINER_TAG
> docker stop CONTAINER_TAG
> rm docker CONTAINER_ID
> rmi docker image_id
</code>```

[ running on a default mac terminal ]

The containers in fact were created from custom images, running from node and a standard redis. My OS is OSX 10.11.6.

At the end of the day I see I keep losing Mbs. How can I face this problem?

EDITED POST

2020 and the problem persists, leaving this update for the community:

Today running:

macOS 10.13.6

Docker Engine 18.9.2

Docker Desktop Cli 2.0.0.3

The easiest way to workaround the problem is to prune the system with the Docker utilties.

```<code>docker system prune -a --volumes
</code>```

答:
Why does the file keep growing?

If Docker is used regularly, the size of the  Docker.raw  (or  Docker.qcow2) can keep growing, even when files are deleted.

To demonstrate the effect, first check the  current  size of the file on the host:

```<code>$ cd ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/
$ ls -s Docker.raw
9964528 Docker.raw
</code>```

Note the use of  -s  which displays the number of filesystem blocks actually used by the file. The number of blocks used is not necessarily the same as the file “size”, as the file can be  sparse.

Next start a container in a separate terminal and create a 1GiB file in it:

```<code>$ docker run -it alpine sh
# and then inside the container:
/ # dd if=/dev/zero of=1GiB bs=1048576 count=1024
1024+0 records in
1024+0 records out
/ # sync
</code>```

Back on the host check the file size again:

```<code>$ ls -s Docker.raw
12061704 Docker.raw
</code>```

Note the increase in size from  9964528  to  12061704, where the increase of  2097176  512-byte sectors is approximately 1GiB, as expected. If you switch back to the  alpine  container terminal and delete the file:

```<code>/ # rm -f 1GiB
/ # sync
</code>```

then check the file on the host:

```<code>$ ls -s Docker.raw
12059672 Docker.raw
</code>```

The file has not got any smaller! Whatever has happened to the file inside the VM, the host doesn’t seem to know about it.

Next if you re-create the “same”  1GiB  file in the container again and then check the size again you will see:

```<code>$ ls -s Docker.raw
14109456 Docker.raw
</code>```

It’s got even bigger! It seems that if you create and destroy files in a loop, the size of the  Docker.raw  (or  Docker.qcow2) will increase up to the upper limit (currently set to 64 GiB), even if the filesystem inside the VM is relatively empty.

The explanation for this odd behaviour lies with how filesystems typically manage blocks. When a file is to be created or extended, the filesystem will find a free block and add it to the file. When a file is removed, the blocks become “free” from the filesystem’s point of view, but no-one tells the disk device. Making matters worse, the newly-freed blocks might not be re-used straight away – it’s completely up to the filesystem’s block allocation algorithm. For example, the algorithm might be designed to favour allocating blocks contiguously for a file: recently-freed blocks are unlikely to be in the ideal place for the file being extended.

Since the block allocator in practice tends to favour unused blocks, the result is that the  Docker.raw  (or  Docker.qcow2) will constantly accumulate new blocks, many of which contain stale data. The file on the host gets larger and larger, even though the filesystem inside the VM still reports plenty of free space.

TRIM

A  TRIM  command (or a  DISCARD  or  UNMAP) allows a filesystem to signal to a disk that a range of sectors contain stale data and they can be forgotten. This allows:

an SSD drive to erase and reuse the space, rather than spend time shuffling it around; and

Docker for Mac to deallocate the blocks in the host filesystem, shrinking the file.

So how do we make this work?

Automatic TRIM in Docker for Mac

In Docker for Mac 17.11 there is a  containerd  “task” called  trim-after-delete  listening for Docker image deletion events. It can be seen via the  ctr  command:

```<code>$ docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n ctr t ls
TASK                    PID     STATUS
vsudd                   1741    RUNNING
acpid                   871     RUNNING
diagnose                913     RUNNING
docker-ce               958     RUNNING
host-timesync-daemon    1046    RUNNING
ntpd                    1109    RUNNING
trim-after-delete       1339    RUNNING
vpnkit-forwarder        1550    RUNNING
</code>```

When an image deletion event is received, the process waits for a few seconds (in case other images are being deleted, for example as part of a  docker system prune  ) and then runs  fstrim  on the filesystem.

Returning to the example in the previous section, if you delete the 1 GiB file inside the  alpine  container

```<code>/ # rm -f 1GiB
</code>```

then run  fstrim  manually from a terminal in the host:

```<code>$ docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n fstrim /var/lib/docker
</code>```

then check the file size:

```<code>$ ls -s Docker.raw
9965016 Docker.raw
</code>```

The file is back to (approximately) it’s original size – the space has finally been freed!

Hopefully this blog will be helpful, also checkout the following macos docker utility scripts for this problem:

https://github.com/wanliqun/macos_docker_toolkit

Title: Docker filling up storage on macOS

Body:
(Post created on Oct 05 '16)

I noticed that every time I run an image and delete it, my system doesn't return to the original amount of available space.

The lifecycle I'm applying to my containers is:

> docker build ...
> docker run CONTAINER_TAG
> docker stop CONTAINER_TAG
> rm docker CONTAINER_ID
> rmi docker image_id

[ running on a default mac terminal ]

The containers in fact were created from custom images, running from node and a standard redis. My OS is OSX 10.11.6.

At the end of the day I see I keep losing Mbs. How can I face this problem?

EDITED POST

2020 and the problem persists, leaving this update for the community:

Today running:

macOS 10.13.6

Docker Engine 18.9.2

Docker Desktop Cli 2.0.0.3

The easiest way to workaround the problem is to prune the system with the Docker utilties.

docker system prune -a --volumes

Body:
Why does the file keep growing?

If Docker is used regularly, the size of the  Docker.raw  (or  Docker.qcow2) can keep growing, even when files are deleted.

To demonstrate the effect, first check the  current  size of the file on the host:

$ cd ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/
$ ls -s Docker.raw
9964528 Docker.raw

Note the use of  -s  which displays the number of filesystem blocks actually used by the file. The number of blocks used is not necessarily the same as the file “size”, as the file can be  sparse.

Next start a container in a separate terminal and create a 1GiB file in it:

$ docker run -it alpine sh
# and then inside the container:
/ # dd if=/dev/zero of=1GiB bs=1048576 count=1024
1024+0 records in
1024+0 records out
/ # sync

Back on the host check the file size again:

$ ls -s Docker.raw
12061704 Docker.raw

Note the increase in size from  9964528  to  12061704, where the increase of  2097176  512-byte sectors is approximately 1GiB, as expected. If you switch back to the  alpine  container terminal and delete the file:

/ # rm -f 1GiB
/ # sync

then check the file on the host:

$ ls -s Docker.raw
12059672 Docker.raw

The file has not got any smaller! Whatever has happened to the file inside the VM, the host doesn’t seem to know about it.

Next if you re-create the “same”  1GiB  file in the container again and then check the size again you will see:

$ ls -s Docker.raw
14109456 Docker.raw

It’s got even bigger! It seems that if you create and destroy files in a loop, the size of the  Docker.raw  (or  Docker.qcow2) will increase up to the upper limit (currently set to 64 GiB), even if the filesystem inside the VM is relatively empty.

The explanation for this odd behaviour lies with how filesystems typically manage blocks. When a file is to be created or extended, the filesystem will find a free block and add it to the file. When a file is removed, the blocks become “free” from the filesystem’s point of view, but no-one tells the disk device. Making matters worse, the newly-freed blocks might not be re-used straight away – it’s completely up to the filesystem’s block allocation algorithm. For example, the algorithm might be designed to favour allocating blocks contiguously for a file: recently-freed blocks are unlikely to be in the ideal place for the file being extended.

Since the block allocator in practice tends to favour unused blocks, the result is that the  Docker.raw  (or  Docker.qcow2) will constantly accumulate new blocks, many of which contain stale data. The file on the host gets larger and larger, even though the filesystem inside the VM still reports plenty of free space.

TRIM

A  TRIM  command (or a  DISCARD  or  UNMAP) allows a filesystem to signal to a disk that a range of sectors contain stale data and they can be forgotten. This allows:

an SSD drive to erase and reuse the space, rather than spend time shuffling it around; and

Docker for Mac to deallocate the blocks in the host filesystem, shrinking the file.

So how do we make this work?

Automatic TRIM in Docker for Mac

In Docker for Mac 17.11 there is a  containerd  “task” called  trim-after-delete  listening for Docker image deletion events. It can be seen via the  ctr  command:

$ docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n ctr t ls
TASK                    PID     STATUS
vsudd                   1741    RUNNING
acpid                   871     RUNNING
diagnose                913     RUNNING
docker-ce               958     RUNNING
host-timesync-daemon    1046    RUNNING
ntpd                    1109    RUNNING
trim-after-delete       1339    RUNNING
vpnkit-forwarder        1550    RUNNING

When an image deletion event is received, the process waits for a few seconds (in case other images are being deleted, for example as part of a  docker system prune  ) and then runs  fstrim  on the filesystem.

Returning to the example in the previous section, if you delete the 1 GiB file inside the  alpine  container

/ # rm -f 1GiB

then run  fstrim  manually from a terminal in the host:

$ docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n fstrim /var/lib/docker

then check the file size:

$ ls -s Docker.raw
9965016 Docker.raw

The file is back to (approximately) it’s original size – the space has finally been freed!

Hopefully this blog will be helpful, also checkout the following macos docker utility scripts for this problem:

https://github.com/wanliqun/macos_docker_toolkit


来源: stackexchange

问:
NoMethodError: undefined method `more_results' for #<Mysql>
I am trying to create rake task to import data from my old php application.But I can not connect to mysql database properly, when I run Old::User.all on rails console ,I get this error :

```<code>NoMethodError: undefined method `more_results' for #<Mysql>

        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/connection_adapters/mysql_adapter.rb:623:in `select'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/connection_adapters/abstract/database_statements.rb:7:in `select_all'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/connection_adapters/abstract/query_cache.rb:56:in `select_all'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/base.rb:467:in `find_by_sql'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/relation.rb:64:in `to_a'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/relation/finder_methods.rb:143:in `all'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/base.rb:439:in `__send__'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/base.rb:439:in `all'
        from (irb):1
</code>```

Model class Old/user.rb

```<code>class Old::User < ActiveRecord::Base
  establish_connection "old_database"

  # Because table name is lowercase
  def self.table_name()
    "user"
  end
end
</code>```

database.yml

```<code>old_database:
  adapter: mysql
  database: old_database
  username: root
  password:
  socket: /Applications/MAMP/tmp/mysql/mysql.sock
</code>```

答:
The latest MySQL gem (=>0.3.2) needs an additional gem to connect -- it's been architected just like the MSSQL-Server gem was in previous versions of Rails.

You also probably want to use the mysql2 (note the "2") gem

ContentLicense: CC BY-SA 2.5

Body:
I am trying to create rake task to import data from my old php application.But I can not connect to mysql database properly, when I run Old::User.all on rails console ,I get this error :

NoMethodError: undefined method `more_results' for #<Mysql>

        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/connection_adapters/mysql_adapter.rb:623:in `select'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/connection_adapters/abstract/database_statements.rb:7:in `select_all'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/connection_adapters/abstract/query_cache.rb:56:in `select_all'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/base.rb:467:in `find_by_sql'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/relation.rb:64:in `to_a'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/relation/finder_methods.rb:143:in `all'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/base.rb:439:in `__send__'
        from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/base.rb:439:in `all'
        from (irb):1

Model class Old/user.rb

class Old::User < ActiveRecord::Base
  establish_connection "old_database"

  # Because table name is lowercase
  def self.table_name()
    "user"
  end
end

database.yml

old_database:
  adapter: mysql
  database: old_database
  username: root
  password:
  socket: /Applications/MAMP/tmp/mysql/mysql.sock

ContentLicense: CC BY-SA 3.0


问:
How do fread and fwrite distinguish between different data (types) in C?
I am working with a program and C (with Ubuntu and its bash) and using it to manipulate binary data files. First of all, when I use fopen(filename, 'w') it creates a file but without any extension. However, when I use vim filename it opens it up in some binary form.

For this question, when I use fwrite(array, sizeof(some struct), # of structs, filePointer) it writes (which I am not sure how in binary) into the file. When I use fread(anotherArray, sizeof(same struct), same # of structs, anotherFilePointer) it somehow magically knows how to read each struct in binary form and puts it into the array just by knowing its size and how much to read. What happens if I put a decimal value less than the number of structs there are in the # of structs parameter? How would fread know what to read correctly? How does it work in reading data just by looking at the sizes and not knowing what type of data it is?

答:
In question comments from @David C. Rankin

"Well, fread/fwrite read and write bytes (binary data - if you write out then read in the same number of bytes -- you get the same thing back). If you want to read and write text where you need to worry about line-breaks, etc.., fgets/fputs. or fprintf"

So I guess I can never know what I read in with fread unless I know what I wrote to it in with fwriite?

"Right, look at the type for your buffer in fwrite(3) - Linux man page it is type void *. It's just a starting address for fwrite to use in writing however many bytes you told it to write. (obviously you know what it is writing) The same for fread -- it just reads bytes -- you have to know what you are reading (or at least the format of it). That's what binary I/O is about, it's all just bytes -- it's up to you, the Programmer, to know what you are writing and reading and how to unpack it. Otherwise, use formatted-I/O and lines, words, etc.."

ContentLicense: CC BY-SA 4.0


问:
Can't set content type from using uploadFile method in @azure/storage-blob (SDK/NPM)
Can't set azure content type from node using below code. It's always storing content type as octane stream.

```<code>const { BlobServiceClient } = require('@azure/storage-blob');

const { AZURE_STORAGE_CONNECTION_STRING } = process.env;

let blobServiceClient;

async function getBlobServiceClient() {
  if (!blobServiceClient) {
    blobServiceClient = await BlobServiceClient.fromConnectionString(AZURE_STORAGE_CONNECTION_STRING);
  }

  return blobServiceClient;
}

async function uploadFile(filePath, containerName) {
  const bsClient = await getBlobServiceClient();
  const containerClient = bsClient.getContainerClient(containerName);
  const blockBlobClient = containerClient.getBlockBlobClient('myImag6.png', { blobHTTPHeaders: { blobContentType: 'image/png' } });

  try {
    const res = await blockBlobClient.uploadFile(filePath);
    console.log(res);
  } catch (error) {
    console.log(error);
  }
}
</code>```

The following issue seems related to this but I am not sure.
https://github.com/Azure/azure-sdk-for-js/issues/6192

Please give me more info on this and how to solve this issue.

答:
Suppose it's because you don't set the BlockBlobUploadOptions in the uploadFile method, you only use it in the getBlockBlobClient method, in my below code test, it could set the content type.

```<code>    const { BlobServiceClient, StorageSharedKeyCredential } = require("@azure/storage-blob");

    // Enter your storage account name and shared key
    const account = "account name";
    const accountKey = "account key";

    const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);
    const blobServiceClient = new BlobServiceClient(
      `https://${account}.blob.core.windows.net`,
      sharedKeyCredential
    );

    const containerName = "test";

    async function main() {
  const containerClient = blobServiceClient.getContainerClient(containerName);

  const blockBlobClient = containerClient.getBlockBlobClient('test.txt');
  const blobOptions = { blobHTTPHeaders: { blobContentType: 'text/plain' } };
  const uploadBlobResponse = await blockBlobClient.uploadFile('E:\\project\\jsstorage\\test.txt',blobOptions);

  console.log(`Upload block blob test.txt successfully`, uploadBlobResponse.requestId);
}

main();
</code>```

Body:
Can't set azure content type from node using below code. It's always storing content type as octane stream.

const { BlobServiceClient } = require('@azure/storage-blob');

const { AZURE_STORAGE_CONNECTION_STRING } = process.env;

let blobServiceClient;

async function getBlobServiceClient() {
  if (!blobServiceClient) {
    blobServiceClient = await BlobServiceClient.fromConnectionString(AZURE_STORAGE_CONNECTION_STRING);
  }

  return blobServiceClient;
}

async function uploadFile(filePath, containerName) {
  const bsClient = await getBlobServiceClient();
  const containerClient = bsClient.getContainerClient(containerName);
  const blockBlobClient = containerClient.getBlockBlobClient('myImag6.png', { blobHTTPHeaders: { blobContentType: 'image/png' } });

  try {
    const res = await blockBlobClient.uploadFile(filePath);
    console.log(res);
  } catch (error) {
    console.log(error);
  }
}

The following issue seems related to this but I am not sure.
https://github.com/Azure/azure-sdk-for-js/issues/6192

Please give me more info on this and how to solve this issue.

Body:
Suppose it's because you don't set the BlockBlobUploadOptions in the uploadFile method, you only use it in the getBlockBlobClient method, in my below code test, it could set the content type.

    const { BlobServiceClient, StorageSharedKeyCredential } = require("@azure/storage-blob");

    // Enter your storage account name and shared key
    const account = "account name";
    const accountKey = "account key";

    const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);
    const blobServiceClient = new BlobServiceClient(
      `https://${account}.blob.core.windows.net`,
      sharedKeyCredential
    );

    const containerName = "test";

    async function main() {
  const containerClient = blobServiceClient.getContainerClient(containerName);

  const blockBlobClient = containerClient.getBlockBlobClient('test.txt');
  const blobOptions = { blobHTTPHeaders: { blobContentType: 'text/plain' } };
  const uploadBlobResponse = await blockBlobClient.uploadFile('E:\\project\\jsstorage\\test.txt',blobOptions);

  console.log(`Upload block blob test.txt successfully`, uploadBlobResponse.requestId);
}

main();


问:
How to load parameters with different values based on user role in Symfony?
I have a multitude of parameters in parameters.yml file, each parameter should have a different value based on logged in user's role.

Is there is way to systematically decide and load correct value based on logged in user's role?

Example:

```<code>parameters:
    user.address_code
    manager.address_code
</code>```

Ideally, I don't want to add conditions in my code for manager or user before I use address_code.

答:
Since parameters values are used during the container compilation, their value cannot be changed at runtime.

And since the user role can only be known during a request, what you want to do simply cannot be done.

But you are most likely you are approaching the problem from the wrong end.

Just encapsulate the logic in a service of some kind. A simplistic example:

The service:

namespace App\Service;

class FooService
{

    private array $configuration;

    public function __construct(array $configuration)
    {
        $this->configuration = $configuration;
    }

    public function getAddressCodeFor(string $role): string
    {
        return $this->configuration[$role] ?? '';
    }
}
```

<p>Your parameters:</p>

```# services.yaml
parameters:
    address_code:
        ROLE_USER: 'foo'
        ROLE_ADMIN: 'bar'
```

<p>Configuration to make sure the service know about your parameters:</p>

```#services.yaml

App\Service\FooService:
    arguments: ['%address_code%']
```

<p>Then it's only a matter of injecting <code>FooService</code> wherever you need these values, and call <code>getAddressCodeFor($role)</code> where you need it:</p>

```class FakeController extends AbstractController
{

    private FooService $paramService;

    public function __construct(FooService $service)
    {
        $this->paramService = $service;
    }

    public function someAction(): Response
    {
        $address_code = $this->paramService->getAddressCodeFor('ROLE_ADMIN');

        return $this->json(['address_code' => $address_code]);
    }

}
```

This is just an example, but you can adjust it to follow your needs.

Body:
I have a multitude of parameters in parameters.yml file, each parameter should have a different value based on logged in user's role.

Is there is way to systematically decide and load correct value based on logged in user's role?

Example:

parameters:
    user.address_code
    manager.address_code

Ideally, I don't want to add conditions in my code for manager or user before I use address_code.

Body:
Since parameters values are used during the container compilation, their value cannot be changed at runtime.

And since the user role can only be known during a request, what you want to do simply cannot be done.

But you are most likely you are approaching the problem from the wrong end.

Just encapsulate the logic in a service of some kind. A simplistic example:

The service:

namespace App\Service;

class FooService
{

    private array $configuration;

    public function __construct(array $configuration)
    {
        $this->configuration = $configuration;
    }

    public function getAddressCodeFor(string $role): string
    {
        return $this->configuration[$role] ?? '';
    }
}

Your parameters:

# services.yaml
parameters:
    address_code:
        ROLE_USER: 'foo'
        ROLE_ADMIN: 'bar'

Configuration to make sure the service know about your parameters:

#services.yaml

App\Service\FooService:
    arguments: ['%address_code%']

Then it's only a matter of injecting FooService wherever you need these values, and call getAddressCodeFor($role) where you need it:

class FakeController extends AbstractController
{

    private FooService $paramService;

    public function __construct(FooService $service)
    {
        $this->paramService = $service;
    }

    public function someAction(): Response
    {
        $address_code = $this->paramService->getAddressCodeFor('ROLE_ADMIN');

        return $this->json(['address_code' => $address_code]);
    }

}

This is just an example, but you can adjust it to follow your needs.


答:
Did you try setting the blobHttpHeaders and passed to the uploadFile method?</p>

```<code>const blobOptions = { blobHTTPHeaders: { blobContentType: 'image/png' } };
const res = await blockBlobClient.uploadFile(filePath, blobOptions);
</code>```

Title: Can't set content type from using uploadFile method in @azure/storage-blob (SDK/NPM)

Body:
Did you try setting the blobHttpHeaders and passed to the uploadFile method?

const blobOptions = { blobHTTPHeaders: { blobContentType: 'image/png' } };
const res = await blockBlobClient.uploadFile(filePath, blobOptions);


问:
could not open git/commit_editmsg
I have a git repository linked to a dropbox folder.
Recently, I have switched my laptop to another, and now i can not perform the function "git commit -am". I keep getting this error message:
"could not open '.git/COMMIT_EDITMSG': Permission denied.

Any ideas?

Thanks,
Liron

答: Ensure that the git app you use (whether GUI, cmd or bash) is running as an Administrator. This of course apply if you are using Windows. </p>

Title: could not open git/commit_editmsg


问:
Advice: where to situate html table content: in JS or HTML
SHORT: my python code generates a webpage with a table.  i'm considering rewriting it to generate a js file instead, that holds the table contents in an array ... and then let the table be generated client-side. I am not sure of the pros and cons.  Anyone care to offer their experience/insight?  Are there other solutions?

LONG: the web page contains a single table and an embedded gmap.  the table is a set of locations with several columns of location-stats and also two navigation columns.  one nav column consists of onclicks that will recenter embedded gmap to the lat,lon of the location.  the other nav column consists of hrefs that open a new window with a gmap centered on the lat,lon.

Until recently, my python code would do some number crunching on a list of files, and then generate the html file. also i wrote a js file that keeps the webpage liquid upon browser window resizing.

Recently, I modified my python code so that it:

placed the lat,lon info in a custom attribute of the tr elements

no longer produced the nav column tds

and then wrote a js function that

loops through the trs onLoad

reads the lat,lon from the custom attribute

inserts the nav tds

fwiw, this reduced the size of the html file by 70% while increasing the js by 10%.

ok, so now I am debating if I should go all the way and write my python code to generate 2 files

an essentially abstract html file

a js file containing a js array of the locations and their stats

答:
If your API can output a JSON document with your data, you gain significant flexibility and future-proofing.  This might even be something your users will want to access directly for their own external consumption.  And of course your JS code can easily generate a table from this data.

However nobody here can tell you whether this is worth doing or not, as that depends entirely on the scope of your project and opportunity cost of time spent re-architecting.


问:
Get dynamic object from query parameters
Is there a way to get a dynamic object from query parameters in an ASP.NET Core WebAPI controller action?

When I try the following I get queries as an empty object

```<code>public object Action([FromQuery] dynamic queries)
{
    ...
}
</code>```

答:
Here is a workaround of customizing a model binder to bind the query string to Dictionary type:

DynamicModelBinder

```<code>public class DynamicModelBinder:IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));

        var result = new Dictionary<string, dynamic> { };
        var query = bindingContext.HttpContext.Request.Query;
        if (query == null)
        {
            bindingContext.ModelState.AddModelError("QueryString", "The data is null");
            return Task.CompletedTask;
        }

        foreach (var k in query.Keys)
        {
            StringValues v = string.Empty;
            var flag = query.TryGetValue(k, out v);
            if (flag)
            {
                if (v.Count > 1)
                {
                    result.Add(k, v);
                }
                else {
                result.Add(k, v[0]);

                }
            }
        }

        bindingContext.Result = ModelBindingResult.Success(result);
        return Task.CompletedTask;
    }
}
</code>```

Controller

```<code>public object Action([ModelBinder(BinderType = typeof(DynamicModelBinder))]dynamic queries)
    {
        return queries;
    }
</code>```

Result

Body:
Is there a way to get a dynamic object from query parameters in an ASP.NET Core WebAPI controller action?

When I try the following I get queries as an empty object

public object Action([FromQuery] dynamic queries)
{
    ...
}

Body:
Here is a workaround of customizing a model binder to bind the query string to Dictionary type:

DynamicModelBinder

public class DynamicModelBinder:IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));

        var result = new Dictionary<string, dynamic> { };
        var query = bindingContext.HttpContext.Request.Query;
        if (query == null)
        {
            bindingContext.ModelState.AddModelError("QueryString", "The data is null");
            return Task.CompletedTask;
        }

        foreach (var k in query.Keys)
        {
            StringValues v = string.Empty;
            var flag = query.TryGetValue(k, out v);
            if (flag)
            {
                if (v.Count > 1)
                {
                    result.Add(k, v);
                }
                else {
                result.Add(k, v[0]);

                }
            }
        }

        bindingContext.Result = ModelBindingResult.Success(result);
        return Task.CompletedTask;
    }
}

Controller

public object Action([ModelBinder(BinderType = typeof(DynamicModelBinder))]dynamic queries)
    {
        return queries;
    }

Result


问:
How to use Azure managed identity with Azure.Storage.Blobs.BlobServiceClient?
In v11 SDK for .NET I was able to use managed identity tokens to get access to Azure blob:

```<code>var token = await new AzureServiceTokenProvider().GetAccessTokenAsync("https://storage.azure.com/");
var tokenCredential = new TokenCredential(token);
var storageCredentials = new StorageCredentials(tokenCredential);
var blob = new CloudBlobContainer(new Uri("https://some_storage.blob.core.windows.net/some_container"), storageCredentials);
</code>```

Now I want to switch to v12 SDK and can't understand how to do the same for BlobServiceClient.

答:
I have a sample: https://github.com/juunas11/managedidentity-filesharing/blob/8410ed3f3d4061de7d40531c025bf6e474489135/Joonasw.ManagedIdentityFileSharingDemo/Services/AzureBlobStorageService.cs#L80

Here is how it is used with Azure.Identity:

```<code>client = new BlobServiceClient(
    new Uri($"https://{_options.AccountName}.blob.core.windows.net"),
    new ManagedIdentityCredential());
</code>```

If you need to run against an Azure Storage account locally, you can use a custom TokenCredential, like here: https://github.com/juunas11/Joonasw.ManagedIdentityDemos/blob/3501ee6fff416db7349807e588532da5c3dd24b1/Joonasw.ManagedIdentityDemos/Services/DemoService.cs#L45.

Custom TokenCredential: https://github.com/juunas11/Joonasw.ManagedIdentityDemos/blob/master/Joonasw.ManagedIdentityDemos/Services/ManagedIdentityStorageTokenCredential.cs.

Usage against Storage Emulator:

```<code>client = new BlobServiceClient("UseDevelopmentStorage=true");
</code>```

Body:
In v11 SDK for .NET I was able to use managed identity tokens to get access to Azure blob:

var token = await new AzureServiceTokenProvider().GetAccessTokenAsync("https://storage.azure.com/");
var tokenCredential = new TokenCredential(token);
var storageCredentials = new StorageCredentials(tokenCredential);
var blob = new CloudBlobContainer(new Uri("https://some_storage.blob.core.windows.net/some_container"), storageCredentials);

Now I want to switch to v12 SDK and can't understand how to do the same for BlobServiceClient.

Body:
I have a sample: https://github.com/juunas11/managedidentity-filesharing/blob/8410ed3f3d4061de7d40531c025bf6e474489135/Joonasw.ManagedIdentityFileSharingDemo/Services/AzureBlobStorageService.cs#L80

Here is how it is used with Azure.Identity:

client = new BlobServiceClient(
    new Uri($"https://{_options.AccountName}.blob.core.windows.net"),
    new ManagedIdentityCredential());

If you need to run against an Azure Storage account locally, you can use a custom TokenCredential, like here: https://github.com/juunas11/Joonasw.ManagedIdentityDemos/blob/3501ee6fff416db7349807e588532da5c3dd24b1/Joonasw.ManagedIdentityDemos/Services/DemoService.cs#L45.

Custom TokenCredential: https://github.com/juunas11/Joonasw.ManagedIdentityDemos/blob/master/Joonasw.ManagedIdentityDemos/Services/ManagedIdentityStorageTokenCredential.cs.

Usage against Storage Emulator:

client = new BlobServiceClient("UseDevelopmentStorage=true");


问:
(Pentaho PDI):Thread: Couldn't find starting point in this job
Pentaho running job through command line

I have a pentaho job which runs successfully in pentaho but if i try to run the same through command line i get the error -(But It runs Successfully in one PC throws, error in another PC)

Here is my problem of the moment:

2016/12/12 16:52:30 - Start of job execution

2016/12/12 16:52:30 - ERROR (version 6.0.0.0-353, build 1 from 2015-10-07

13.27.43 by buildguy) : A serious error occurred during job execution:

2016/12/12 16:52:30 - Couldn't find starting point in this job.

2016/12/12 16:52:30 - ERROR (version 6.0.0.0-353, build 1 from 2015-10-07

13.27.43 by buildguy) : org.pentaho.di.core.exception.KettleJobException:

2016/12/12 16:52:30 - Couldn't find starting point in this job.

2016/12/12 16:52:30 -   at org.pentaho.di.job.Job.execute(Job.java:532)

2016/12/12 16:52:30 -   at org.pentaho.di.job.Job.run(Job.java:435)

2016/12/12 16:52:30 - Kitchen - Finished!

2016/12/12 16:52:30 - Kitchen - ERROR (version 6.0.0.0-353, build 1 from

2015-10-07 13.27.43 by buildguy) : Finished with errors

2016/12/12 16:52:30 - Kitchen - Start=2016/12/12 16:52:15.536, Stop=2016/12/12 16:52:30.652

答:
you should try pan, pan is PDI command line tools.

PDI Command line tools

```<code>sh /home/patel/Downloads/pdi/pdi-ce-9.0.0.0-423/data-integration/pan.sh /file:/home/patel/Documents/replication.ktr
</code>```

Body:
you should try pan, pan is PDI command line tools.

PDI Command line tools

sh /home/patel/Downloads/pdi/pdi-ce-9.0.0.0-423/data-integration/pan.sh /file:/home/patel/Documents/replication.ktr


问:
.NET Core Entity Framework Fluent api error, DateTime properties have text as column type
In my model namespace, I have different model classes. I have DateTime fields in my different classes. When I run

```<code>dotnet ef migrations add InitialCreate
</code>```

without problem, it adds a migration and I am able to update the database too.

When I looked up my initialCommit.Designer.cs, I saw that all of my DateTime properties have column type text.

Like this:

```<code>namespace myapp.API.Models
{
    public class User
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        public string Gender { get; set; }
        public DateTime BirthDate { get; set; }
        public string KnownAs { get; set; }
        public DateTime CreatedOn { get; set; }
        public DateTime LastActive { get; set; }
        ..
    }
}

namespace myapp.API.Models
{
    public class Photo
    {
        public int Id { get; set; }
        public string Url { get; set; }
        public string Description { get; set; }
        public DateTime DateAdded { get; set; }
        public bool IsMain { get; set; }
        public string PublicId  { get; set; }
        public User User { get; set; }
        public int UserId { get; set; }
    }
}

namespace myapp.API.Migrations
{
    [DbContext(typeof(DataContext))]
    [Migration("20200206201625_initialCommit")]
    partial class initialCommit
    {
        protected override void BuildTargetModel(ModelBuilder modelBuilder)
        {
#pragma warning disable 612, 618
            modelBuilder
                .HasAnnotation("ProductVersion", "3.1.1");

            modelBuilder.Entity("myapp.API.Models.Photo", b =>
                {
                    b.Property<int>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("INTEGER");

                    b.Property<DateTime>("DateAdded")
                        .HasColumnType("TEXT");

                    b.Property<string>("Description")
                        .HasColumnType("TEXT");

                    b.Property<bool>("IsMain")
                        .HasColumnType("INTEGER");

                    b.Property<string>("PublicId")
                        .HasColumnType("TEXT");

                    b.Property<string>("Url")
                        .HasColumnType("TEXT");

                    b.Property<int>("UserId")
                        .HasColumnType("INTEGER");

                    b.HasKey("Id");

                    b.HasIndex("UserId");

                    b.ToTable("Photos");
                });

            modelBuilder.Entity("myapp.API.Models.User", b =>
                {
                    b.Property<int>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("INTEGER");

                    b.Property<DateTime>("BirthDate")
                        .HasColumnType("TEXT");

                    b.Property<string>("City")
                        .HasColumnType("TEXT");

                    b.Property<string>("Country")
                        .HasColumnType("TEXT");

                    b.Property<DateTime>("CreatedOn")
                        .HasColumnType("TEXT");

                    b.Property<string>("Gender")
                        .HasColumnType("TEXT");

                    b.Property<string>("Interests")
                        .HasColumnType("TEXT");

                    b.Property<string>("Introduction")
                        .HasColumnType("TEXT");

                    b.Property<string>("KnownAs")
                        .HasColumnType("TEXT");

                    b.Property<DateTime>("LastActive")
                        .HasColumnType("TEXT");

                    b.Property<string>("LookingFor")
                        .HasColumnType("TEXT");

                    b.Property<byte[]>("PasswordHash")
                        .HasColumnType("BLOB");

                    b.Property<byte[]>("PasswordSalt")
                        .HasColumnType("BLOB");

                    b.Property<string>("UserName")
                        .HasColumnType("TEXT");

                    b.HasKey("Id");

                    b.ToTable("Users");
                });

            modelBuilder.Entity("myapp.API.Models.Value", b =>
                {
                    b.Property<int>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("INTEGER");

                    b.Property<string>("Name")
                        .HasColumnType("TEXT");

                    b.Property<string>("Type")
                        .HasColumnType("TEXT");

                    b.HasKey("Id");

                    b.ToTable("Values");
                });

            modelBuilder.Entity("myapp.API.Models.Photo", b =>
                {
                    b.HasOne("myapp.API.Models.User", "User")
                        .WithMany("Photos")
                        .HasForeignKey("UserId")
                        .OnDelete(DeleteBehavior.Cascade)
                        .IsRequired();
                });
#pragma warning restore 612, 618
        }
    }
}
</code>```

As you can see, all of my DateTime fields are defined like this :

```<code>b.Property<DateTime>("DateAdded").HasColumnType("TEXT");
</code>```

答:
you can set the columtype yourself;</p>

```<code>modelBuilder.Entity<User>.Property<b=>BirthDate>().HasColumnType("date");
</code>```

Body:
In my model namespace, I have different model classes. I have DateTime fields in my different classes. When I run

dotnet ef migrations add InitialCreate

without problem, it adds a migration and I am able to update the database too.

When I looked up my initialCommit.Designer.cs, I saw that all of my DateTime properties have column type text.

Like this:

namespace myapp.API.Models
{
    public class User
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        public string Gender { get; set; }
        public DateTime BirthDate { get; set; }
        public string KnownAs { get; set; }
        public DateTime CreatedOn { get; set; }
        public DateTime LastActive { get; set; }
        ..
    }
}

namespace myapp.API.Models
{
    public class Photo
    {
        public int Id { get; set; }
        public string Url { get; set; }
        public string Description { get; set; }
        public DateTime DateAdded { get; set; }
        public bool IsMain { get; set; }
        public string PublicId  { get; set; }
        public User User { get; set; }
        public int UserId { get; set; }
    }
}

namespace myapp.API.Migrations
{
    [DbContext(typeof(DataContext))]
    [Migration("20200206201625_initialCommit")]
    partial class initialCommit
    {
        protected override void BuildTargetModel(ModelBuilder modelBuilder)
        {
#pragma warning disable 612, 618
            modelBuilder
                .HasAnnotation("ProductVersion", "3.1.1");

            modelBuilder.Entity("myapp.API.Models.Photo", b =>
                {
                    b.Property<int>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("INTEGER");

                    b.Property<DateTime>("DateAdded")
                        .HasColumnType("TEXT");

                    b.Property<string>("Description")
                        .HasColumnType("TEXT");

                    b.Property<bool>("IsMain")
                        .HasColumnType("INTEGER");

                    b.Property<string>("PublicId")
                        .HasColumnType("TEXT");

                    b.Property<string>("Url")
                        .HasColumnType("TEXT");

                    b.Property<int>("UserId")
                        .HasColumnType("INTEGER");

                    b.HasKey("Id");

                    b.HasIndex("UserId");

                    b.ToTable("Photos");
                });

            modelBuilder.Entity("myapp.API.Models.User", b =>
                {
                    b.Property<int>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("INTEGER");

                    b.Property<DateTime>("BirthDate")
                        .HasColumnType("TEXT");

                    b.Property<string>("City")
                        .HasColumnType("TEXT");

                    b.Property<string>("Country")
                        .HasColumnType("TEXT");

                    b.Property<DateTime>("CreatedOn")
                        .HasColumnType("TEXT");

                    b.Property<string>("Gender")
                        .HasColumnType("TEXT");

                    b.Property<string>("Interests")
                        .HasColumnType("TEXT");

                    b.Property<string>("Introduction")
                        .HasColumnType("TEXT");

                    b.Property<string>("KnownAs")
                        .HasColumnType("TEXT");

                    b.Property<DateTime>("LastActive")
                        .HasColumnType("TEXT");

                    b.Property<string>("LookingFor")
                        .HasColumnType("TEXT");

                    b.Property<byte[]>("PasswordHash")
                        .HasColumnType("BLOB");

                    b.Property<byte[]>("PasswordSalt")
                        .HasColumnType("BLOB");

                    b.Property<string>("UserName")
                        .HasColumnType("TEXT");

                    b.HasKey("Id");

                    b.ToTable("Users");
                });

            modelBuilder.Entity("myapp.API.Models.Value", b =>
                {
                    b.Property<int>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("INTEGER");

                    b.Property<string>("Name")
                        .HasColumnType("TEXT");

                    b.Property<string>("Type")
                        .HasColumnType("TEXT");

                    b.HasKey("Id");

                    b.ToTable("Values");
                });

            modelBuilder.Entity("myapp.API.Models.Photo", b =>
                {
                    b.HasOne("myapp.API.Models.User", "User")
                        .WithMany("Photos")
                        .HasForeignKey("UserId")
                        .OnDelete(DeleteBehavior.Cascade)
                        .IsRequired();
                });
#pragma warning restore 612, 618
        }
    }
}

As you can see, all of my DateTime fields are defined like this :

b.Property<DateTime>("DateAdded").HasColumnType("TEXT");

Body:
you can set the columtype yourself;

modelBuilder.Entity<User>.Property<b=>BirthDate>().HasColumnType("date");


问:
Foreach loop group by XML element value
I want to group them by agent

XML structured as follows

```<code><library>
    <document>
        <ProductName>somename1</ProductName>
        <productAgent>Agent-01</productAgent>
        <productType>Goods</productType>
    </document>
        <ProductName>somename3</ProductName>
        <productAgent>Agent-02</productAgent>
        <productType>Services</productType>
    </document>
    ......
</library>
</code>```

Expecting Output

```<code><ul>
    <li>Agent-01(productAgent)
        <ul>
            <li>somename1 - Goods</li>
        </ul>
    </li>
    <li>Agent-02(productAgent)
        <ul>
            <li>somename3 - Services</li>
            <li>somename6 - Goods</li>
        </ul>
    </li>
</ul>
</code>```

What I tried

```<code><ul>
    <li>Agent-01(productAgent)
        <ul>
            <?php foreach($xml->document as $item){
                if ($item->productAgent == 'Agent-01' ) {
                    echo '<li>'.$item->ProductName.'-'.$item->ProductType.'</li>';
                }
            }
            ?>
        </ul>
    </li>
    <li>Agent-02(productAgent)
        <ul>
            <?php foreach($xml->document as $item){
                if ($item->productAgent == 'Agent-02' ) {
                    echo '<li>'.$item->ProductName.'-'.$item->ProductType.'</li>';
                }
            }
            ?>
        </ul>
    </li>
</ul>
</code>```

Problem

I have to modify my code every time the agent name change. My code doesn't seem to be a good solution when the number of agent increase.

答:
Collect all data to array, where key is agent and value is array of products:</p>

```<code><?php
$values = [];
foreach($xml->document as $item){
    $agent = (string) $item->productAgent;
    if (!isset($values[$agent])) {
        $values[$agent] = [];
    }

    $values[$agent][] = (string) $item->ProductName;
    // add other tags as you need:
    //$values[$agent][] = [
    //    'name' => (string) $item->ProductName,
    //    'type' => (string) $item->ProductType,
    //];
}

// Then iterate over this array and output as needed
foreach ($values as $agent => $products) {
    echo $agent . ': ' . implode(', ', $products);
    // iterate over $products and output what you need
}?>
</code>```

Title: Foreach loop group by XML element value

Body:
I want to group them by agent

XML structured as follows

<library>
    <document>
        <ProductName>somename1</ProductName>
        <productAgent>Agent-01</productAgent>
        <productType>Goods</productType>
    </document>
        <ProductName>somename3</ProductName>
        <productAgent>Agent-02</productAgent>
        <productType>Services</productType>
    </document>
    ......
</library>

Expecting Output

Agent-01(productAgent)

somename1 - Goods

Agent-02(productAgent)

somename3 - Services

somename6 - Goods

What I tried

Agent-01(productAgent)

            <?php foreach($xml->document as $item){
                if ($item->productAgent == 'Agent-01' ) {
                    echo '
'.$item->ProductName.'-'.$item->ProductType.'
';
                }
            }
            ?>

Agent-02(productAgent)

            <?php foreach($xml->document as $item){
                if ($item->productAgent == 'Agent-02' ) {
                    echo '
'.$item->ProductName.'-'.$item->ProductType.'
';
                }
            }
            ?>

Problem

I have to modify my code every time the agent name change. My code doesn't seem to be a good solution when the number of agent increase.

Body:
Collect all data to array, where key is agent and value is array of products:

<?php
$values = [];
foreach($xml->document as $item){
    $agent = (string) $item->productAgent;
    if (!isset($values[$agent])) {
        $values[$agent] = [];
    }

    $values[$agent][] = (string) $item->ProductName;
    // add other tags as you need:
    //$values[$agent][] = [
    //    'name' => (string) $item->ProductName,
    //    'type' => (string) $item->ProductType,
    //];
}

// Then iterate over this array and output as needed
foreach ($values as $agent => $products) {
    echo $agent . ': ' . implode(', ', $products);
    // iterate over $products and output what you need
}?>


问:
Ajax form data pass
How can I pass the form data on my PHP file? I have tried the below solution but it was not worked for me. I need to pass all checkboxes on my PHP function.I have tried but not getting the perfect value that I need?

Please check the issue and guide me where I was wrong.

```<code><form id="filterForm" method="post">

          <div class="dropdown">
            <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            Beer Brands
            </button>
            <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
              <ul>
                <li><input class="clickBox" type="checkbox" name="beer_brands[]" value="valu1" />Test</li>
                <li><input class="clickBox" type="checkbox" name="beer_brands[]" value="valu2"/>Test</li>
                <li><input class="clickBox" type="checkbox" name="beer_brands[]" value="value3"/>Test</li>
              </ul>
            </div>
          </div>

          <div class="dropdown">
            <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            Locations
            </button>
            <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
              <ul>
                <li><input class="clickBox" type="checkbox" name="locations[]" value="value4" />Test</li>
                <li><input class="clickBox" type="checkbox" name="locations[]" value="value5"/>Test</li>
                <li><input class="clickBox" type="checkbox" name="locations[]" value="value6"/>Test</li>
              </ul>
            </div>
          </div>

          <div class="dropdown">
            <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            Sort By
            </button>
            <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
              <ul>
                <li><input class="clickBox" type="checkbox" name="sort_by[]" value="value7" />Test</li>
                <li><input class="clickBox" type="checkbox" name="sort_by[]" value="value8"/>Test</li>
                <li><input class="clickBox" type="checkbox" name="sort_by[]" value="value9"/>Test</li>
              </ul>
            </div>
          </div>

        </form>
</code>```

JQuery

```<code><script type="text/javascript">
jQuery(document).ready(function(){

  jQuery(".clickBox").click(function(e){

      var b_b_Array  = []
      var location_Array  = []
      var sort_by_Array  = []

      jQuery('.clickBox').each(function ()
      {
          //debugger;
          jQuery("input[name='beer_brands[]']").each( function () {
              if(jQuery('input[name="beer_brands[]"]').is(':checked')) {
                b_b_Array.push(jQuery(this).val());
              }
          });

          jQuery("input[name='locations[]']").each( function () {
              if(jQuery('input[name="locations[]"]').is(':checked')) {

                location_Array.push(jQuery(this).val());
              }
          });

          jQuery("input[name='sort_by[]']").each( function () {
              if(jQuery('input[name="sort_by[]"]').is(':checked')) {

                sort_by_Array.push(jQuery(this).val());
              }
          });

      });

      console.log(b_b_Array);
      console.log(location_Array);
      console.log(sort_by_Array);

      var ajaxurl = "<?php bloginfo('url');?>/wp-admin/admin-ajax.php";

      jQuery.ajax({
          url: ajaxurl,
          type : 'post',
          data: {
            'action':'all_give_aways_filter',
            'data' : jQuery("filterForm").serialize(),
          },
          success : function( response ) {
              console.log(response);
              // jQuery("div#errMsg").css({'background-color':'white','color':'red'});
              // jQuery("div#errMsg").html(response);
          }
      });

  });

});

</script>
</code>```

Please Help me to solve this issue.

答:
Can you try replace this JavaScript. Hope this help you</p>

```<code>function get_checkbox_value(){
    var array = [];
    jQuery(':checkbox:checked').each(function(i, _this){
      var checkboxname = jQuery(_this).attr('name'); checkboxname = checkboxname.replace('[]','');
      array[checkboxname]=[];
      array[checkboxname].push(jQuery(this).val());
    });
    return array;
}

jQuery(document).ready(function(){

    jQuery("#filterForm").submit(function(e){
        e.preventDefault();

        var formdata = get_checkbox_value();
        var ajaxurl = "<?php bloginfo('url');?>/wp-admin/admin-ajax.php";

      jQuery.ajax({
          url: ajaxurl,
          type : 'POST',
          data: {
            'action':'all_give_aways_filter',
            'data' : formdata,
          },
          success : function( response ) {
              console.log(response);
          }
      });
  });
});
</code>```

Title: Ajax form data pass

Body:
How can I pass the form data on my PHP file? I have tried the below solution but it was not worked for me. I need to pass all checkboxes on my PHP function.I have tried but not getting the perfect value that I need?

Please check the issue and guide me where I was wrong.

<form id="filterForm" method="post">

            <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            Beer Brands
            </button>

<input class="clickBox" type="checkbox" name="beer_brands[]" value="valu1" />Test

<input class="clickBox" type="checkbox" name="beer_brands[]" value="valu2"/>Test

<input class="clickBox" type="checkbox" name="beer_brands[]" value="value3"/>Test

            <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            Locations
            </button>

<input class="clickBox" type="checkbox" name="locations[]" value="value4" />Test

<input class="clickBox" type="checkbox" name="locations[]" value="value5"/>Test

<input class="clickBox" type="checkbox" name="locations[]" value="value6"/>Test

            <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            Sort By
            </button>

<input class="clickBox" type="checkbox" name="sort_by[]" value="value7" />Test

<input class="clickBox" type="checkbox" name="sort_by[]" value="value8"/>Test

<input class="clickBox" type="checkbox" name="sort_by[]" value="value9"/>Test

        </form>

JQuery

Please Help me to solve this issue.

Body:
Can you try replace this JavaScript. Hope this help you

function get_checkbox_value(){
    var array = [];
    jQuery(':checkbox:checked').each(function(i, _this){
      var checkboxname = jQuery(_this).attr('name'); checkboxname = checkboxname.replace('[]','');
      array[checkboxname]=[];
      array[checkboxname].push(jQuery(this).val());
    });
    return array;
}

jQuery(document).ready(function(){

    jQuery("#filterForm").submit(function(e){
        e.preventDefault();

        var formdata = get_checkbox_value();
        var ajaxurl = "<?php bloginfo('url');?>/wp-admin/admin-ajax.php";

      jQuery.ajax({
          url: ajaxurl,
          type : 'POST',
          data: {
            'action':'all_give_aways_filter',
            'data' : formdata,
          },
          success : function( response ) {
              console.log(response);
          }
      });
  });
});


问:
How to delete 1 file on 3 files uploaded on vuetify?
I read on the docs : https://vuetifyjs.com/en/components/file-inputs#selection-slot

My code like this :

```<code><v-file-input
  v-model="files"
  placeholder="Upload your documents"
  label="File input"
  multiple
  prepend-icon="mdi-paperclip"
>
  <template v-slot:selection="{ text }">
    <v-chip
      small
      label
      color="primary"
    >
      {{ text }}
    </v-chip>
  </template>
</v-file-input>
</code>```

My codepen : https://codepen.io/positivethinking639/pen/vYONqKa?editable=true&editors=101

When upload 3 images and delete, it will delete all images. I want the user to be able to delete 1 image according to his choice. So the user can delete 1 picture

How can I do it?

答:
Configure the chips to delete with a handler method.

Add 'close' attribute to v-chip to get a close button on each file

Add a handler to the chip, passing index (and text if you want to prompt)

(optional) remove the clear-all button on VFileInput to prevent user confusion

Template

<v-file-input
  ...
  :clearable="false"
>
  <template v-slot:selection="{ index, text }">
    <v-chip
      ...
      close
      @click:close="deleteChip(index, text)"
    >
      {{ text }}
    </v-chip>
  </template>
```

<p><strong>Component</strong></p>

<pre class="lang-js prettyprint-override"><code>new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data: () => ({
    files: [],
  }),
  methods: {
    deleteChip(index, text) {
      // Prompt here with text if required
      this.files.splice(index, 1)
    },
  }
})
</code>```

Body:
I read on the docs : https://vuetifyjs.com/en/components/file-inputs#selection-slot

My code like this :

<v-file-input
  v-model="files"
  placeholder="Upload your documents"
  label="File input"
  multiple
  prepend-icon="mdi-paperclip"
>
  <template v-slot:selection="{ text }">
    <v-chip
      small
      label
      color="primary"
    >
      {{ text }}
    </v-chip>
  </template>
</v-file-input>

My codepen : https://codepen.io/positivethinking639/pen/vYONqKa?editable=true&editors=101

When upload 3 images and delete, it will delete all images. I want the user to be able to delete 1 image according to his choice. So the user can delete 1 picture

How can I do it?

Body:
Configure the chips to delete with a handler method.

Add 'close' attribute to v-chip to get a close button on each file

Add a handler to the chip, passing index (and text if you want to prompt)

(optional) remove the clear-all button on VFileInput to prevent user confusion

Template

<v-file-input
  ...
  :clearable="false"
>
  <template v-slot:selection="{ index, text }">
    <v-chip
      ...
      close
      @click:close="deleteChip(index, text)"
    >
      {{ text }}
    </v-chip>
  </template>

Component

new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data: () => ({
    files: [],
  }),
  methods: {
    deleteChip(index, text) {
      // Prompt here with text if required
      this.files.splice(index, 1)
    },
  }
})


问:
iOS: Get how fast user is moving
I'm wanting to figure out if a user is not moving at all, walking, or running using the iPhone. I'm not trying to implement a pedometer. I just want to know around about if someone is moving briskly, slowly, or not at all. I don't need mph or anything like that.

I think the accelerometer may be able to do this for me, but I was wondering if someone  knows of any tutorials or example code that might be able to point me in the right direction?

Thanks to all that reply

答:
People have a different bounce in their step between walking and running which can be measured with the accelerometer, but this differs between individuals (what shoes they are wearing, what surface they are upon, what part of the body is attached to the iPhone etc.), and this motion can probably be imitated by shaking the iPhone just right while standing still.

Experiment by recording the two types of acceleration profiles, and then use some sort of pattern matching to pick the most likely profile candidate from the current recorded acceleration data.

Title: iOS: Get how fast user is moving


问:
SQL*Loader-926: OCI error while executing delete/truncate ORA-01031: insufficient privileges
I have 12 .csv files which should be loaded in a staging table and after it loaded the data to the staging table it should load the data grouped by parameters into another table. It throws an error by creating the table. It is missing privileges.

GABER_RIGHTS.SQL:

```<code>GRANT SELECT, DELETE, INSERT, UPDATE ON FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB                    TO GABER;
GRANT SELECT, DELETE, INSERT, UPDATE ON FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB_STA        TO GABER;
GRANT SELECT, DELETE, INSERT, UPDATE ON FOOTBALLCLUB.DIM_PLAYER                TO GABER;
GRANT SELECT, DELETE, INSERT, UPDATE ON FOOTBALLCLUB.DIM_TEAM                   TO GABER;
GRANT SELECT, DELETE, INSERT, UPDATE ON FOOTBALLCLUB.DIM_TRAINER                  TO GABER;
exit;
</code>```

gaber_footballclub.sh:

```<code>#!/bin/bash

sqlplus system/oracle @FOOTBALLCLUB_GABER_CREATE_USER.sql
sqlplus gaber/oracle @FOOTBALLCLUB_GABER_CREATE_TABLES.plsql
sqlplus gaber/oracle @FOOTBALLCLUB_GABER_CREATE_TABLES.sql
sqlplus system/oracle @GABER_RIGHTS.sql

for FILE_NAME in `ls ../data/FACT_FOOTBALLCLUB_GABER*.csv`
do
   export BASE_NAME=`basename $FILE_NAME`
   export JUST_NAME=`echo $BASE_NAME | sed -e 's/\..*//'`
   echo $FILE_NAME
   echo $BASE_NAME
   echo $JUST_NAME

sed -e 's/"//g' ../data/$FILE_NAME | dos2unix >../data/FACT_FOOTBALLCLUB_GABER.csv
sqlldr gaber/oracle data=../data/FACT_FOOTBALLCLUB_GABER.csv control=gaber_footballclub_staging.ldr log=../log/$JUST_NAME.log bad=../log/$JUST_NAME.bad errors=20

   sqlplus gaber/oracle <<!
      INSERT INTO FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB
      SELECT
   ID,
   Sum(NUMBER_OF_PLAYERS) as NUMBER_OF_PLAYERS,
   Sum(GOALS_SHOT) as GOALS_SHOT,
   Sum(GOALS_GOT) as GOALS_GOT,
   Sum(YELLOW_CARDS) as YELLOW_CARDS,
   Sum(RED_CARDS) as RED_CARDS,
   Sum(MINUTES_PLAYED) as MINUTES_PLAYED,
   DATE_PLAYED,
   TEAM_ID,
   TRAINER_ID
      FROM   FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB_STA
      GROUP BY ID, DATE_PLAYED, TEAM_ID, TRAINER_ID;
      exit;
!
done
</code>```

gaber_footballclub_staging.ldr:

```<code>LOAD DATA
REPLACE
INTO TABLE FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB_STA
FIELDS TERMINATED BY ','
(
   ID,
   NUMBER_OF_PLAYERS,
   GOALS_SHOT,
   GOALS_GOT,
   YELLOW_CARDS,
   RED_CARDS,
   MINUTES_PLAYED,
   DATE_PLAYED  DATE "YYYY-MM-DD",
   TEAM_ID,
   TRAINER_ID
)
</code>```

FOOTBALLCLUB_GABER_CREATE_USER.sql:

```<code>DROP TABLESPACE TBS_GABER_DWH INCLUDING CONTENTS AND DATAFILES;
DROP USER FOOTBALLCLUB CASCADE;
DROP USER GABER CASCADE;

CREATE SMALLFILE TABLESPACE TBS_GABER_DWH DATAFILE
'/home/oracle/app/oracle/oradata/orcl/gaber_dwh01.dbf' SIZE 200M AUTOEXTEND ON NEXT 10M MAXSIZE UNLIMITED,
'/home/oracle/app/oracle/oradata/orcl/gaber_dwh02.dbf' SIZE 200M AUTOEXTEND ON NEXT 10M MAXSIZE UNLIMITED
LOGGING EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO;

CREATE USER GABER PROFILE DEFAULT IDENTIFIED BY "oracle"
DEFAULT TABLESPACE TBS_GABER_DWH
QUOTA UNLIMITED ON TBS_GABER_DWH
TEMPORARY TABLESPACE TEMP ACCOUNT UNLOCK;
GRANT SELECT ANY DICTIONARY TO GABER;
GRANT UNLIMITED TABLESPACE TO GABER;
GRANT CONNECT TO GABER;
GRANT RESOURCE TO GABER;
GRANT CREATE TABLE TO GABER;
GRANT CREATE ANY TABLE TO GABER;
GRANT CREATE PROCEDURE TO GABER;
GRANT CREATE ANY PROCEDURE TO GABER;
GRANT EXECUTE ANY PROCEDURE TO GABER;
GRANT CREATE SESSION TO GABER;
GRANT SELECT ANY TABLE TO GABER;

CREATE USER FOOTBALLCLUB PROFILE DEFAULT IDENTIFIED BY "oracle"
DEFAULT TABLESPACE TBS_GABER_DWH
TEMPORARY TABLESPACE TEMP
QUOTA UNLIMITED ON TBS_GABER_DWH
ACCOUNT LOCK;
GRANT CREATE TABLE TO FOOTBALLCLUB;
GRANT UNLIMITED TABLESPACE TO FOOTBALLCLUB;

exit;
</code>```

FOOTBALLCLUB_GABER_CREATE_TABLES.sql:

```<code>call FOOTBALLCLUB.PROC_GABER_CREATE_TABLES('FOOTBALLCLUB');
exit;
</code>```

FOOTBALLCLUB_GABER_CREATE_TABLES.plsql:

```<code>CREATE OR REPLACE PROCEDURE FOOTBALLCLUB.PROC_GABER_CREATE_TABLES (SCHEMA_NAME IN VARCHAR2) IS
  v_tabcnt number;
BEGIN

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'DIM_TEAM';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_TEAM
            (
                TEAM_ID  INTEGER      NOT NULL PRIMARY KEY,
                TEAM_NAME VARCHAR2(30)     NOT NULL
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'DIM_PLAYER';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_PLAYER
            (
                PLAYER_ID     INTEGER      NOT NULL PRIMARY KEY,
                PLAYER_NAME   VARCHAR2(30) NOT NULL,
                PLAYER_NUMBER INTEGER NOT NULL,
                PLAYER_BIRTHDATE DATE NOT NULL,
                TEAM_ID INTEGER NOT NULL,

                CONSTRAINT fk_team_id
                   FOREIGN KEY (TEAM_ID)
                   REFERENCES ' || SCHEMA_NAME || '.DIM_TEAM (TEAM_ID)
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'DIM_TRAINER';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_TRAINER
            (
                TRAINER_ID  INTEGER      NOT NULL PRIMARY KEY,
                TRAINER_NAME VARCHAR2(30) NOT NULL,
                TRAINER_BIRTHDATE DATE NOT NULL
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'FACT_GABER_FOOTBALLCLUB_STA';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.FACT_GABER_FOOTBALLCLUB_STA
            (
                ID     INTEGER    NOT NULL PRIMARY KEY,
                NUMBER_OF_PLAYERS     INTEGER NOT NULL,
                GOALS_SHOT  INTEGER NOT NULL,
                GOALS_GOT     INTEGER NOT NULL,
                YELLOW_CARDS    INTEGER NOT NULL,
                RED_CARDS         INTEGER NOT NULL,
                MINUTES_PLAYED        DECIMAL(12,2) NOT NULL,
                DATE_PLAYED       DATE NOT NULL,
                TEAM_ID            INTEGER NOT NULL,
                TRAINER_ID      INTEGER NOT NULL,

                CONSTRAINT fk_fact_team_id_st
                   FOREIGN KEY (TEAM_ID)
                   REFERENCES ' || SCHEMA_NAME || '.DIM_TEAM (TEAM_ID),
                CONSTRAINT fk_trainer_id_st
                   FOREIGN KEY (TRAINER_ID)
                   REFERENCES ' || SCHEMA_NAME || '.DIM_TRAINER (TRAINER_ID)
            )';
  end if;

    SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'FACT_GABER_FOOTBALLCLUB';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.FACT_GABER_FOOTBALLCLUB
            (
                ID     INTEGER    NOT NULL PRIMARY KEY,
                NUMBER_OF_PLAYERS     INTEGER NOT NULL,
                GOALS_SHOT  INTEGER NOT NULL,
                GOALS_GOT     INTEGER NOT NULL,
                YELLOW_CARDS    INTEGER NOT NULL,
                RED_CARDS         INTEGER NOT NULL,
                MINUTES_PLAYED        DECIMAL(12,2) NOT NULL,
                DATE_PLAYED       DATE NOT NULL,
                TEAM_ID            INTEGER NOT NULL,
                TRAINER_ID      INTEGER NOT NULL,
                CONSTRAINT fk_fact_team_id
                   FOREIGN KEY (TEAM_ID)
                   REFERENCES ' || SCHEMA_NAME || '.DIM_TEAM (TEAM_ID),
                CONSTRAINT fk_trainer_id
                   FOREIGN KEY (TRAINER_ID)
                   REFERENCES ' || SCHEMA_NAME || '.DIM_TRAINER (TRAINER_ID)
            )';
  end if;
END;
/
exit;
</code>```

gaber_footballclub_staging.log:
    SQL*Loader: Release 11.2.0.2.0 - Production on Thu Feb 13 15:05:23 2020

```<code>Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

Control File:   gaber_footballclub_staging.ldr
Data File:      ../data/FACT_FOOTBALLCLUB_GABER.csv
  Bad File:     FACT_FOOTBALLCLUB_GABER.bad
  Discard File:  none specified

 (Allow all discards)

Number to load: ALL
Number to skip: 0
Errors allowed: 50
Bind array:     64 rows, maximum of 256000 bytes
Continuation:    none specified
Path used:      Conventional

Table FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB_STA, loaded from every logical record.
Insert option in effect for this table: REPLACE

   Column Name                  Position   Len  Term Encl Datatype
------------------------------ ---------- ----- ---- ---- ---------------------
ID                                  FIRST     *   ;       CHARACTER
NUMBER_OF_PLAYERS                    NEXT     *   ;       CHARACTER
GOALS_SHOT                           NEXT     *   ;       CHARACTER
GOALS_GOT                            NEXT     *   ;       CHARACTER
YELLOW_CARDS                         NEXT     *   ;       CHARACTER
RED_CARDS                            NEXT     *   ;       CHARACTER
MINUTES_PLAYED                       NEXT     *   ;       CHARACTER
DATE_PLAYED                          NEXT     *   ;       DATE YYYY-MM-DD
TEAM_ID                              NEXT     *   ;       CHARACTER
TRAINER_ID                           NEXT     *   ;       CHARACTER

SQL*Loader-926: OCI error while executing delete/truncate (due to REPLACE/TRUNCATE keyword) for table FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB_STA
ORA-01031: insufficient privileges
</code>```

答:
I have solved my problems by deleting the constraints and primary keys in the plsql script. Furthermore, I had one 0 instead of an O in one csv sheet.

The only document that has changed is
FOOTBALLCLUB_GABER_CREATE_TABLES.plsql:

```<code>CREATE OR REPLACE PROCEDURE FOOTBALLCLUB.PROC_GABER_CREATE_TABLES (SCHEMA_NAME IN VARCHAR2) IS
  v_tabcnt number;
BEGIN

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
  TABLE_NAME = 'DIM_TEAM';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_TEAM
            (
                TEAM_ID  INTEGER      NOT NULL,
                TEAM_NAME VARCHAR2(30)     NOT NULL
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'DIM_PLAYER';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_PLAYER
            (
                PLAYER_ID     INTEGER      NOT NULL,
                PLAYER_NAME   VARCHAR2(30) NOT NULL,
                PLAYER_NUMBER INTEGER NOT NULL,
                PLAYER_BIRTHDATE DATE NOT NULL,
                TEAM_ID INTEGER NOT NULL
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'DIM_TRAINER';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_TRAINER
            (
                TRAINER_ID  INTEGER      NOT NULL,
                TRAINER_NAME VARCHAR2(30) NOT NULL,
                TRAINER_BIRTHDATE DATE NOT NULL
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'FACT_GABER_FOOTBALLCLUB_STA';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.FACT_GABER_FOOTBALLCLUB_STA
            (
                ID     INTEGER    NOT NULL,
                NUMBER_OF_PLAYERS     INTEGER NOT NULL,
                GOALS_SHOT  INTEGER NOT NULL,
                GOALS_GOT     INTEGER NOT NULL,
                YELLOW_CARDS    INTEGER NOT NULL,
                RED_CARDS         INTEGER NOT NULL,
                MINUTES_PLAYED        DECIMAL(12,2) NOT NULL,
                DATE_PLAYED       DATE NOT NULL,
                TEAM_ID            INTEGER NOT NULL,
                TRAINER_ID      INTEGER NOT NULL
            )';
  end if;

    SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'FACT_GABER_FOOTBALLCLUB';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.FACT_GABER_FOOTBALLCLUB
            (
                ID     INTEGER    NOT NULL,
                NUMBER_OF_PLAYERS     INTEGER NOT NULL,
                GOALS_SHOT  INTEGER NOT NULL,
                GOALS_GOT     INTEGER NOT NULL,
                YELLOW_CARDS    INTEGER NOT NULL,
                RED_CARDS         INTEGER NOT NULL,
                MINUTES_PLAYED        DECIMAL(12,2) NOT NULL,
                DATE_PLAYED       DATE NOT NULL,
                TEAM_ID            INTEGER NOT NULL,
                TRAINER_ID      INTEGER NOT NULL
            )';
  end if;
END;
/
exit;
</code>```

Body:
I have 12 .csv files which should be loaded in a staging table and after it loaded the data to the staging table it should load the data grouped by parameters into another table. It throws an error by creating the table. It is missing privileges.

GABER_RIGHTS.SQL:

GRANT SELECT, DELETE, INSERT, UPDATE ON FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB                    TO GABER;
GRANT SELECT, DELETE, INSERT, UPDATE ON FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB_STA        TO GABER;
GRANT SELECT, DELETE, INSERT, UPDATE ON FOOTBALLCLUB.DIM_PLAYER                TO GABER;
GRANT SELECT, DELETE, INSERT, UPDATE ON FOOTBALLCLUB.DIM_TEAM                   TO GABER;
GRANT SELECT, DELETE, INSERT, UPDATE ON FOOTBALLCLUB.DIM_TRAINER                  TO GABER;
exit;

gaber_footballclub.sh:

#!/bin/bash

sqlplus system/oracle @FOOTBALLCLUB_GABER_CREATE_USER.sql
sqlplus gaber/oracle @FOOTBALLCLUB_GABER_CREATE_TABLES.plsql
sqlplus gaber/oracle @FOOTBALLCLUB_GABER_CREATE_TABLES.sql
sqlplus system/oracle @GABER_RIGHTS.sql

for FILE_NAME in `ls ../data/FACT_FOOTBALLCLUB_GABER*.csv`
do
   export BASE_NAME=`basename $FILE_NAME`
   export JUST_NAME=`echo $BASE_NAME | sed -e 's/\..*//'`
   echo $FILE_NAME
   echo $BASE_NAME
   echo $JUST_NAME

sed -e 's/"//g' ../data/$FILE_NAME | dos2unix >../data/FACT_FOOTBALLCLUB_GABER.csv
sqlldr gaber/oracle data=../data/FACT_FOOTBALLCLUB_GABER.csv control=gaber_footballclub_staging.ldr log=../log/$JUST_NAME.log bad=../log/$JUST_NAME.bad errors=20

   sqlplus gaber/oracle <<!
      INSERT INTO FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB
      SELECT
   ID,
   Sum(NUMBER_OF_PLAYERS) as NUMBER_OF_PLAYERS,
   Sum(GOALS_SHOT) as GOALS_SHOT,
   Sum(GOALS_GOT) as GOALS_GOT,
   Sum(YELLOW_CARDS) as YELLOW_CARDS,
   Sum(RED_CARDS) as RED_CARDS,
   Sum(MINUTES_PLAYED) as MINUTES_PLAYED,
   DATE_PLAYED,
   TEAM_ID,
   TRAINER_ID
      FROM   FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB_STA
      GROUP BY ID, DATE_PLAYED, TEAM_ID, TRAINER_ID;
      exit;
!
done

gaber_footballclub_staging.ldr:

LOAD DATA
REPLACE
INTO TABLE FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB_STA
FIELDS TERMINATED BY ','
(
   ID,
   NUMBER_OF_PLAYERS,
   GOALS_SHOT,
   GOALS_GOT,
   YELLOW_CARDS,
   RED_CARDS,
   MINUTES_PLAYED,
   DATE_PLAYED  DATE "YYYY-MM-DD",
   TEAM_ID,
   TRAINER_ID
)

FOOTBALLCLUB_GABER_CREATE_USER.sql:

DROP TABLESPACE TBS_GABER_DWH INCLUDING CONTENTS AND DATAFILES;
DROP USER FOOTBALLCLUB CASCADE;
DROP USER GABER CASCADE;

CREATE SMALLFILE TABLESPACE TBS_GABER_DWH DATAFILE
'/home/oracle/app/oracle/oradata/orcl/gaber_dwh01.dbf' SIZE 200M AUTOEXTEND ON NEXT 10M MAXSIZE UNLIMITED,
'/home/oracle/app/oracle/oradata/orcl/gaber_dwh02.dbf' SIZE 200M AUTOEXTEND ON NEXT 10M MAXSIZE UNLIMITED
LOGGING EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO;

CREATE USER GABER PROFILE DEFAULT IDENTIFIED BY "oracle"
DEFAULT TABLESPACE TBS_GABER_DWH
QUOTA UNLIMITED ON TBS_GABER_DWH
TEMPORARY TABLESPACE TEMP ACCOUNT UNLOCK;
GRANT SELECT ANY DICTIONARY TO GABER;
GRANT UNLIMITED TABLESPACE TO GABER;
GRANT CONNECT TO GABER;
GRANT RESOURCE TO GABER;
GRANT CREATE TABLE TO GABER;
GRANT CREATE ANY TABLE TO GABER;
GRANT CREATE PROCEDURE TO GABER;
GRANT CREATE ANY PROCEDURE TO GABER;
GRANT EXECUTE ANY PROCEDURE TO GABER;
GRANT CREATE SESSION TO GABER;
GRANT SELECT ANY TABLE TO GABER;

CREATE USER FOOTBALLCLUB PROFILE DEFAULT IDENTIFIED BY "oracle"
DEFAULT TABLESPACE TBS_GABER_DWH
TEMPORARY TABLESPACE TEMP
QUOTA UNLIMITED ON TBS_GABER_DWH
ACCOUNT LOCK;
GRANT CREATE TABLE TO FOOTBALLCLUB;
GRANT UNLIMITED TABLESPACE TO FOOTBALLCLUB;

exit;

FOOTBALLCLUB_GABER_CREATE_TABLES.sql:

call FOOTBALLCLUB.PROC_GABER_CREATE_TABLES('FOOTBALLCLUB');
exit;

FOOTBALLCLUB_GABER_CREATE_TABLES.plsql:

CREATE OR REPLACE PROCEDURE FOOTBALLCLUB.PROC_GABER_CREATE_TABLES (SCHEMA_NAME IN VARCHAR2) IS
  v_tabcnt number;
BEGIN

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'DIM_TEAM';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_TEAM
            (
                TEAM_ID  INTEGER      NOT NULL PRIMARY KEY,
                TEAM_NAME VARCHAR2(30)     NOT NULL
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'DIM_PLAYER';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_PLAYER
            (
                PLAYER_ID     INTEGER      NOT NULL PRIMARY KEY,
                PLAYER_NAME   VARCHAR2(30) NOT NULL,
                PLAYER_NUMBER INTEGER NOT NULL,
                PLAYER_BIRTHDATE DATE NOT NULL,
                TEAM_ID INTEGER NOT NULL,

                CONSTRAINT fk_team_id
                   FOREIGN KEY (TEAM_ID)
                   REFERENCES ' || SCHEMA_NAME || '.DIM_TEAM (TEAM_ID)
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'DIM_TRAINER';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_TRAINER
            (
                TRAINER_ID  INTEGER      NOT NULL PRIMARY KEY,
                TRAINER_NAME VARCHAR2(30) NOT NULL,
                TRAINER_BIRTHDATE DATE NOT NULL
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'FACT_GABER_FOOTBALLCLUB_STA';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.FACT_GABER_FOOTBALLCLUB_STA
            (
                ID     INTEGER    NOT NULL PRIMARY KEY,
                NUMBER_OF_PLAYERS     INTEGER NOT NULL,
                GOALS_SHOT  INTEGER NOT NULL,
                GOALS_GOT     INTEGER NOT NULL,
                YELLOW_CARDS    INTEGER NOT NULL,
                RED_CARDS         INTEGER NOT NULL,
                MINUTES_PLAYED        DECIMAL(12,2) NOT NULL,
                DATE_PLAYED       DATE NOT NULL,
                TEAM_ID            INTEGER NOT NULL,
                TRAINER_ID      INTEGER NOT NULL,

                CONSTRAINT fk_fact_team_id_st
                   FOREIGN KEY (TEAM_ID)
                   REFERENCES ' || SCHEMA_NAME || '.DIM_TEAM (TEAM_ID),
                CONSTRAINT fk_trainer_id_st
                   FOREIGN KEY (TRAINER_ID)
                   REFERENCES ' || SCHEMA_NAME || '.DIM_TRAINER (TRAINER_ID)
            )';
  end if;

    SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'FACT_GABER_FOOTBALLCLUB';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.FACT_GABER_FOOTBALLCLUB
            (
                ID     INTEGER    NOT NULL PRIMARY KEY,
                NUMBER_OF_PLAYERS     INTEGER NOT NULL,
                GOALS_SHOT  INTEGER NOT NULL,
                GOALS_GOT     INTEGER NOT NULL,
                YELLOW_CARDS    INTEGER NOT NULL,
                RED_CARDS         INTEGER NOT NULL,
                MINUTES_PLAYED        DECIMAL(12,2) NOT NULL,
                DATE_PLAYED       DATE NOT NULL,
                TEAM_ID            INTEGER NOT NULL,
                TRAINER_ID      INTEGER NOT NULL,
                CONSTRAINT fk_fact_team_id
                   FOREIGN KEY (TEAM_ID)
                   REFERENCES ' || SCHEMA_NAME || '.DIM_TEAM (TEAM_ID),
                CONSTRAINT fk_trainer_id
                   FOREIGN KEY (TRAINER_ID)
                   REFERENCES ' || SCHEMA_NAME || '.DIM_TRAINER (TRAINER_ID)
            )';
  end if;
END;
/
exit;

gaber_footballclub_staging.log:
    SQL*Loader: Release 11.2.0.2.0 - Production on Thu Feb 13 15:05:23 2020

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

Control File:   gaber_footballclub_staging.ldr
Data File:      ../data/FACT_FOOTBALLCLUB_GABER.csv
  Bad File:     FACT_FOOTBALLCLUB_GABER.bad
  Discard File:  none specified

 (Allow all discards)

Number to load: ALL
Number to skip: 0
Errors allowed: 50
Bind array:     64 rows, maximum of 256000 bytes
Continuation:    none specified
Path used:      Conventional

Table FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB_STA, loaded from every logical record.
Insert option in effect for this table: REPLACE

   Column Name                  Position   Len  Term Encl Datatype
------------------------------ ---------- ----- ---- ---- ---------------------
ID                                  FIRST     *   ;       CHARACTER
NUMBER_OF_PLAYERS                    NEXT     *   ;       CHARACTER
GOALS_SHOT                           NEXT     *   ;       CHARACTER
GOALS_GOT                            NEXT     *   ;       CHARACTER
YELLOW_CARDS                         NEXT     *   ;       CHARACTER
RED_CARDS                            NEXT     *   ;       CHARACTER
MINUTES_PLAYED                       NEXT     *   ;       CHARACTER
DATE_PLAYED                          NEXT     *   ;       DATE YYYY-MM-DD
TEAM_ID                              NEXT     *   ;       CHARACTER
TRAINER_ID                           NEXT     *   ;       CHARACTER

SQL*Loader-926: OCI error while executing delete/truncate (due to REPLACE/TRUNCATE keyword) for table FOOTBALLCLUB.FACT_GABER_FOOTBALLCLUB_STA
ORA-01031: insufficient privileges

Body:
I have solved my problems by deleting the constraints and primary keys in the plsql script. Furthermore, I had one 0 instead of an O in one csv sheet.

The only document that has changed is
FOOTBALLCLUB_GABER_CREATE_TABLES.plsql:

CREATE OR REPLACE PROCEDURE FOOTBALLCLUB.PROC_GABER_CREATE_TABLES (SCHEMA_NAME IN VARCHAR2) IS
  v_tabcnt number;
BEGIN

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
  TABLE_NAME = 'DIM_TEAM';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_TEAM
            (
                TEAM_ID  INTEGER      NOT NULL,
                TEAM_NAME VARCHAR2(30)     NOT NULL
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'DIM_PLAYER';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_PLAYER
            (
                PLAYER_ID     INTEGER      NOT NULL,
                PLAYER_NAME   VARCHAR2(30) NOT NULL,
                PLAYER_NUMBER INTEGER NOT NULL,
                PLAYER_BIRTHDATE DATE NOT NULL,
                TEAM_ID INTEGER NOT NULL
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'DIM_TRAINER';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.DIM_TRAINER
            (
                TRAINER_ID  INTEGER      NOT NULL,
                TRAINER_NAME VARCHAR2(30) NOT NULL,
                TRAINER_BIRTHDATE DATE NOT NULL
            )';
  end if;

  SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'FACT_GABER_FOOTBALLCLUB_STA';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.FACT_GABER_FOOTBALLCLUB_STA
            (
                ID     INTEGER    NOT NULL,
                NUMBER_OF_PLAYERS     INTEGER NOT NULL,
                GOALS_SHOT  INTEGER NOT NULL,
                GOALS_GOT     INTEGER NOT NULL,
                YELLOW_CARDS    INTEGER NOT NULL,
                RED_CARDS         INTEGER NOT NULL,
                MINUTES_PLAYED        DECIMAL(12,2) NOT NULL,
                DATE_PLAYED       DATE NOT NULL,
                TEAM_ID            INTEGER NOT NULL,
                TRAINER_ID      INTEGER NOT NULL
            )';
  end if;

    SELECT count(*) into v_tabcnt
  FROM   ALL_TABLES
  WHERE  OWNER = SCHEMA_NAME and
         TABLE_NAME = 'FACT_GABER_FOOTBALLCLUB';

  if v_tabcnt = 0 then
      EXECUTE IMMEDIATE
            'CREATE TABLE ' || SCHEMA_NAME || '.FACT_GABER_FOOTBALLCLUB
            (
                ID     INTEGER    NOT NULL,
                NUMBER_OF_PLAYERS     INTEGER NOT NULL,
                GOALS_SHOT  INTEGER NOT NULL,
                GOALS_GOT     INTEGER NOT NULL,
                YELLOW_CARDS    INTEGER NOT NULL,
                RED_CARDS         INTEGER NOT NULL,
                MINUTES_PLAYED        DECIMAL(12,2) NOT NULL,
                DATE_PLAYED       DATE NOT NULL,
                TEAM_ID            INTEGER NOT NULL,
                TRAINER_ID      INTEGER NOT NULL
            )';
  end if;
END;
/
exit;


问:
All tabs keeps rebuilding when changing from one to another
I have a problem this problem where I change between the four tabs and every time I click on one of them, all 4 widgets within CupertinoTabView are rebuild.

I tried changing the ternary to a switch but the result is the same.
Also tried using automatickeepaliveclientmixin on all 4 pages (with super on build method and the wantKeepAlive getter), but it's no use.

The code for this part is as follows:

class _MainTabsState extends State<MainTabs> {

  _buildCartButton(index) {
    // Some code I do here
  }

  int index = 0;

  @override
  Widget build(BuildContext context) {
    return CupertinoTabScaffold(
      tabBar: CupertinoTabBar(
        items: [
          BottomNavigationBarItem(
            title: Text(I18n.of(context).home, style: TextStyle(fontSize: 12.0)),
            icon: Icon(Icons.home),
          ),
          BottomNavigationBarItem(
            title: Text(I18n.of(context).search, style: TextStyle(fontSize: 12.0)),
            icon: Icon(Icons.search),
          ),
          _buildCartButton(index),
          BottomNavigationBarItem(
            title: Text(I18n.of(context).user, style: TextStyle(fontSize: 12.0)),
            icon: Icon(Icons.person),
          ),
        ],
        activeColor: Colors.orange,
        currentIndex: index,
        onTap: (ind) {
          setState(() {
            index = ind;
          });
        },
      ),
      tabBuilder: (context, i) {
        return CupertinoTabView(builder: (context) {
          return (i == 0)
              ? HomePage()
              : (i == 1) ? SearchPage() : (i == 2) ? CartPage() : UserPage();
        });
      },
    );
  }
}

```

<p>I just print something at the start of each page's build method and I see 4 prints every time I change tabs.</p>

<p>Also I'm using Cupertino because I need to keep the bottom bar persistent across the pages (I use a navigator on HomePage that leads to another screen and I need the bottom bar showing there, for example).</p>

<p>Edit: here's the code of one of the pages. I do a print in every page and every time i click one of the tabs I see the print on my terminal.</p>

<pre class="lang-dart prettyprint-override"><code>class HomePage extends StatefulWidget {
  HomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin {
  _changeLanguage(CartModel model) {
    if (I18n.of(context).toString() == 'Instance of \'_I18n_en_US\'') {
      I18n.onLocaleChanged(Locale('pt', 'BR'));
      model.changeCurrency('BRL');
    }
    if (I18n.of(context).toString() == 'Instance of \'_I18n_pt_BR\'') {
      I18n.onLocaleChanged(Locale('en', 'US'));
      model.changeCurrency('USD');
    }
  }

  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);

    print('hi home');
    return Scaffold(
    ...
</code>```

答:
You need to add AutomaticKeepAliveClientMixin to each of the Tab's widgets. For example:

```<code>class _SearchPageState State extends State<SearchPage> with AutomaticKeepAliveClientMixin{
</code>```

This will make sure your pages aren't rebuilt every time the user changes tabs.

Body:
I have a problem this problem where I change between the four tabs and every time I click on one of them, all 4 widgets within CupertinoTabView are rebuild.

I tried changing the ternary to a switch but the result is the same.
Also tried using automatickeepaliveclientmixin on all 4 pages (with super on build method and the wantKeepAlive getter), but it's no use.

The code for this part is as follows:

class _MainTabsState extends State<MainTabs> {

  _buildCartButton(index) {
    // Some code I do here
  }

  int index = 0;

  @override
  Widget build(BuildContext context) {
    return CupertinoTabScaffold(
      tabBar: CupertinoTabBar(
        items: [
          BottomNavigationBarItem(
            title: Text(I18n.of(context).home, style: TextStyle(fontSize: 12.0)),
            icon: Icon(Icons.home),
          ),
          BottomNavigationBarItem(
            title: Text(I18n.of(context).search, style: TextStyle(fontSize: 12.0)),
            icon: Icon(Icons.search),
          ),
          _buildCartButton(index),
          BottomNavigationBarItem(
            title: Text(I18n.of(context).user, style: TextStyle(fontSize: 12.0)),
            icon: Icon(Icons.person),
          ),
        ],
        activeColor: Colors.orange,
        currentIndex: index,
        onTap: (ind) {
          setState(() {
            index = ind;
          });
        },
      ),
      tabBuilder: (context, i) {
        return CupertinoTabView(builder: (context) {
          return (i == 0)
              ? HomePage()
              : (i == 1) ? SearchPage() : (i == 2) ? CartPage() : UserPage();
        });
      },
    );
  }
}

I just print something at the start of each page's build method and I see 4 prints every time I change tabs.

Also I'm using Cupertino because I need to keep the bottom bar persistent across the pages (I use a navigator on HomePage that leads to another screen and I need the bottom bar showing there, for example).

Edit: here's the code of one of the pages. I do a print in every page and every time i click one of the tabs I see the print on my terminal.

class HomePage extends StatefulWidget {
  HomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin {
  _changeLanguage(CartModel model) {
    if (I18n.of(context).toString() == 'Instance of \'_I18n_en_US\'') {
      I18n.onLocaleChanged(Locale('pt', 'BR'));
      model.changeCurrency('BRL');
    }
    if (I18n.of(context).toString() == 'Instance of \'_I18n_pt_BR\'') {
      I18n.onLocaleChanged(Locale('en', 'US'));
      model.changeCurrency('USD');
    }
  }

  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);

    print('hi home');
    return Scaffold(
    ...

Body:
You need to add AutomaticKeepAliveClientMixin to each of the Tab's widgets. For example:

class _SearchPageState State extends State<SearchPage> with AutomaticKeepAliveClientMixin{

This will make sure your pages aren't rebuilt every time the user changes tabs.


问:
Why do PostgreSQL functions return null columns instead of no rows when the return type is a table name?
If I create a function f that queries a function I think it becomes easier to read if the return type is the name of a table instead of RETURNS TABLE(id integer, name text).

```<code>CREATE TABLE users ( id integer, name text );

CREATE OR REPLACE FUNCTION f()
 RETURNS users
 AS $$
   SELECT * FROM users
   WHERE FALSE
 $$
 LANGUAGE SQL;
</code>```

But I'm getting weird results when the query in the function is returning zero rows.

```<code>SELECT * FROM f();
</code>```

Expected result

+------+--------+
| id   | name   |
|------+--------|
+------+--------+

```

<p><em>Actual result</em></p>

<pre class="lang-none prettyprint-override"><code>+--------+--------+
| id     | name   |
|--------+--------|
| <null> | <null> |
+--------+--------+
</code>```

If there are more columns they will still all be null. If the query in the function returns any rows then it works as expected. I'm not getting this behaviour if I'm using the RETURNS TABLE(...) syntax.

Is there a way to get around this?

I'm using PostgreSQL 9.6

答:
That has nothing to do with the return type, but with the fact that you declared the function as returning a single row.

Replace

```<code>RETURNS users
</code>```

with

```<code>RETURNS SETOF users
</code>```

and your function will work as expected.

As your function is, it will return NULLs if the query has no results, and it will return the first row if the query has more than one result rows.

Body:
If I create a function f that queries a function I think it becomes easier to read if the return type is the name of a table instead of RETURNS TABLE(id integer, name text).

CREATE TABLE users ( id integer, name text );

CREATE OR REPLACE FUNCTION f()
 RETURNS users
 AS $$
   SELECT * FROM users
   WHERE FALSE
 $$
 LANGUAGE SQL;

But I'm getting weird results when the query in the function is returning zero rows.

SELECT * FROM f();

Expected result

+------+--------+
| id   | name   |
|------+--------|
+------+--------+

Actual result

+--------+--------+
| id     | name   |
|--------+--------|
| <null> | <null> |
+--------+--------+

If there are more columns they will still all be null. If the query in the function returns any rows then it works as expected. I'm not getting this behaviour if I'm using the RETURNS TABLE(...) syntax.

Is there a way to get around this?

I'm using PostgreSQL 9.6

Body:
That has nothing to do with the return type, but with the fact that you declared the function as returning a single row.

Replace

RETURNS users

with

RETURNS SETOF users

and your function will work as expected.

As your function is, it will return NULLs if the query has no results, and it will return the first row if the query has more than one result rows.